1. 程式人生 > >30分鐘全面解析-SQL事務+隔離級別+阻塞+死鎖

30分鐘全面解析-SQL事務+隔離級別+阻塞+死鎖

 以前總是追求新東西,發現基礎才是最重要的,今年主要的目標是精通SQL查詢和SQL效能優化。

 本系列主要是針對T-SQL的總結。

概述:

本篇主要是對SQL中事務和併發的詳細講解。

一、事務

1.什麼是事務

為單個工作單元而執行的一系列操作。如查詢、修改資料、修改資料定義。

2.語法

(1)顯示定義事務的開始、提交

BEGIN TRAN
INSERT INTO b(t1) VALUES(1)
INSERT INTO b(t1) VALUES(2)
COMMIT TRAN

(2)隱式定義

如果不顯示定義事務的邊界,則SQL Server會預設把每個單獨的語句作為一個事務,即在執行完每個語句之後就會自動提交事務。

3.事務的四個屬性ACID

(1)原子性Atomicity

1.事務必須是原子工作單元。事務中進行的修改,要麼全部執行,要麼全都不執行;

2.在事務完成之前(提交指令被記錄到事務日誌之前),系統出現故障或重新啟動,SQL Server將會撤銷在事務中進行的所有修改;

3.事務在處理中遇到錯誤,SQL Server通常會自動回滾事務;

4.少數不太嚴重的錯誤不會引發事務的自動回滾,如主鍵衝突、鎖超時等;

5.可以使用錯誤處理來捕獲第4點提到的錯誤,並採取某種操作,如把錯誤記錄在日誌中,再回滾事務;

6.SELECT @@TRANCOUNT可用在程式碼的任何位置來判斷當前使用SELECT @@TRANCOUNT的地方是否位於一個開啟的事務當中,如果不在任何開啟的事務範圍內,則該函式返回0;如果在某個開啟的事務返回範圍內,則返回一個大於0的值。開啟一個事務,@@

[email protected]@TRANCOUNT+1;提交一個事務,@@TRANCOUNT-1。

(2)一致性Consiitency

1.同時發生的事務在修改和查詢資料時不發生衝突;

2.一致性取決於應用程式的需要。後面會講到一致性級別,以及如何對一致性進行控制。

(3)隔離性Isolation

1.用於控制資料訪問,確保事務只訪問處於期望的一致性級別下的資料;

2.使用鎖對各個事務之間正在修改和查詢的資料進行隔離。

(4)永續性Durability

1.在將資料修改寫入到磁碟上資料庫的資料分割槽之前會把這些修改寫入到磁碟上資料庫的事務日誌中,把提交指令記錄到磁碟的事務日誌中以後,及時資料修改還沒有應用到磁碟的資料分割槽,也可以認為事務時持久化的。

2.系統重新啟動(正常啟動或在發生系統故障之後啟動),SQL Server會每個資料庫的事務日誌,進行回覆處理。

3.恢復處理包含兩個階段:重做階段和撤銷階段。

4.前滾:在重做階段,對於提交指令已經寫入到日誌的事務,但資料修改還沒有應用到資料分割槽的事務,資料庫引擎會重做這些食物所做的所有修改。

5.回滾:在撤銷階段,對於提交指令沒有寫入到日誌中的事務,資料庫引擎會撤銷這些事務所做的修改。(這句話需要research,可能是不正確的。因為提交指令沒有寫入到資料分割槽,撤銷修改是指撤銷哪些修改呢???)

二、鎖

1.事務中的鎖

(1)SQL Server使用鎖來實現事務的隔離。

(2)事務獲取鎖這種控制資源,用於保護資料資源,防止其他事務對資料進行衝突的或不相容的訪問。

2.鎖模式

(1)排他鎖

  a.當試圖修改資料時,事務只能為所依賴的資料資源請求排他鎖。

  b.持有排他鎖時間:一旦某個事務得到了排他鎖,則這個事務將一直持有排他鎖直到事務完成。

  c.排他鎖和其他任何型別的鎖在多事務中不能在同一階段作用於同一個資源。

    如:當前事務獲得了某個資源的排他鎖,則其他事務不能獲得該資源的任何其他型別的鎖。其他事務獲得了某個資源的任何其他型別的鎖,則當前事務不能獲得該資源的排他鎖。

(2)共享鎖

  a.當試圖讀取資料時,事務預設會為所依賴的資料資源請求共享鎖。

  b.持有共享鎖時間:從事務得到共享鎖到讀操作完成。

  c.多個事務可以在同一階段用共享鎖作用於同一資料資源。

  d.在讀取資料時,可以對如何處理鎖定進行控制。後面隔離級別會講到如何對鎖定進行控制。

3.排他鎖和共享鎖的相容性

(1)如果資料正在由一個事務進行修改,則其他事務既不能修改該資料,也不能讀取(至少預設不能)該資料,直到第一個事務完成。

(2)如果資料正在由一個事務讀取,則其他事務不能修改該資料(至少預設不能)。

4.可鎖定的資源的型別

RID、KEY(行)、PAGE(頁)、物件(例如表)、資料庫、EXTENT(區)、分配單元(ALLOCATION_UNIT)、堆(HEAP)、以及B樹(B-tree)。

RID: 標識頁上的特定行
  格式: fileid: pagenumber: rid (1:109:0 )
    其中fileid標識包含頁的檔案, pagenumber標識包含行的頁,rid標識頁上的特定行。
    fileid與sys.databases_files 目錄檢視中的file_id列相匹配
  例子:
    在查詢檢視sys.dm_tran_locks的時候有一行的resource_description列顯示RID 是1:109:0 而status列顯示wait,
    表示第1個數據檔案上的第109頁上的第0行上的鎖資源。

5.鎖升級

SQL Server可以先獲得細粒度的鎖(例如行或頁),在某些情況下將細粒度鎖升級為更粗粒度的鎖(例如,表)。
例如單個語句獲得至少5000個鎖,就會觸發鎖升級,如果由於鎖衝突而導致無法升級鎖,則SQL Server每當獲取1250個新鎖時出發鎖升級。

三、阻塞

1.阻塞

當多個事務都需要對某一資源進行鎖定時,預設情況下會發生阻塞。被阻塞的請求會一直等待,直到原來的事務釋放相關的鎖。鎖定超時期限可以限制,這樣就可以限制被阻塞的請求在超時之前要等待的時間。

階段1:事務A請求資源S1,事務不對資源S1進行操作

階段2:事務A用鎖A鎖定資源S1,事務B請求對資源S1進行不相容的鎖定(鎖B),鎖B的請求被阻塞,事務B將進入等待狀態

階段3:事務A正在釋放鎖A,事務B等待鎖A釋放,

階段4:事務A的鎖A已釋放,事務B用鎖B鎖定資源S1

2.排除阻塞

例子:

(1)準備工作:

  1.準備測試資料

--先建立一張表Product作為測試。id為表的主鍵,price為product的價格
CREATE TABLE [dbo].[myProduct](
	[id] [int] NOT NULL,
	[price] [money] NOT NULL
) ON [PRIMARY]
GO
--插入一條資料,id=1,price=10
INSERT INTO [TSQLFundamentals2008].[dbo].[myProduct]([id],[price])VALUES(1,10)

  2.模擬阻塞發生的情況

   在SQL Server中開啟三個查詢視窗Connection1、Connection2、Connection3,分別按順序執行表格中的執行語句。

--Connection1
BEGIN TRAN
UPDATE dbo.myProduct SET price = price + 1 WHERE id=1
 
--Connection2
SELECT * FROM dbo.myProduct WHERE id=1
 
--Connection3
SELECT  request_session_id AS 會話id ,
		resource_type AS 請求鎖定的資源型別 ,
		resource_description AS 描述 ,
		request_mode AS 模式 ,
		request_status AS 狀態
FROM    sys.dm_tran_locks
查詢視窗

伺服器程序識別符號SPID


執行語句 

結果  說明 
 Connection1 52  
--語句1:
BEGIN TRAN
UPDATE dbo.myProduct SET price = price + 1 WHERE id=1

更新產品價格10.00->11.00
   

為了更新id=1這一行資料,會話必須先獲得一個排他鎖。事務處於一直開啟狀態,沒有提交,所以事務一直持有排他鎖,直到事務提交併完成。

 Connection2 56   
--語句2:
SELECT * FROM dbo.myProduct WHERE id=1
   

事務為了讀取資料,需要請求一個共享鎖,但是這一行已經被其他會話持有的排他鎖鎖定,而且共享鎖和排他鎖不是相容的,所以會話被阻塞,進入等待狀態

 Connection3 57   
--語句3:
SELECT request_session_id AS 會話id ,
resource_type AS 請求鎖定的資源型別 ,
resource_description AS 描述 ,
request_mode AS 模式 ,
request_status AS 狀態
FROM sys.dm_tran_locks
   

會話56:
(1)狀態WAIT-等待鎖
(2)正在等待第1個數據檔案上的第109頁上的第0行資源的共享鎖
(3)持有第1個數據檔案上的第109頁資源的意向共享鎖
(3)持有OBJECT資源,意向共享鎖
(4)持有DATABASE資源,意向共享鎖
會話52:
(1)狀態WAIT-授予鎖
(2)正在等待第1個數據檔案上的第109頁上的第0行資源的排他鎖(3)持有第1個數據檔案上的第109頁資源的排他鎖
(3)持有OBJECT資源,排他鎖
(4)持有DATABASE資源,排他鎖

(2)分析阻塞

★ 1.sys.dm_tran_locks 檢視

(1)該動態檢視可以查詢出哪些資源被哪個程序ID鎖了

(2)查詢出對資源授予或正在等待的鎖模式

(3)查詢出被鎖定資源的型別

上面的查詢語句3已經用到了這個檢視,可以參考上圖中的分析說明。

★ 2.sys.dm_exec_connections 檢視

(1)查詢出該動態檢視可以查詢出程序相關的資訊

(2)查詢出最後一次發生讀操作和寫操作的時間last_read,last_write

(3)查詢出程序執行的最後一個SQL批處理的二進位制標記most_recent_sql_handle

查詢視窗

伺服器程序識別符號SPID


執行語句 

結果  說明 
 Connection3 57   
SELECT  session_id ,
        connect_time ,
        last_read ,
        last_write ,
        most_recent_sql_handle
FROM    sys.dm_exec_connections

WHERE   session_id IN ( 52, 56 )

 

會話52:
(1)connect_time連線時間:2016-06-07 07:09:41.103
(2)last_read最後一次讀操作時間:2016-06-07 07:10:56.233
(3)last_write最後一次寫操作時間:2016-06-07 07:10:57.873
(4)most_recent_sql_handle這是一個二進位制標記,最後一個SQL批處理

會話56:
(1)狀態WAIT-授予鎖
(2)正在等待第1個數據檔案上的第109頁上的第0行資源的排他鎖(3)持有第1個數據檔案上的第109頁資源的排他鎖
(3)持有OBJECT資源,排他鎖
(4)持有DATABASE資源,排他鎖

★ 3.sys.dm_exec_sql_text 表函式

(1)該函式可以將二進位制標記most_recent_sql_handle作為引數,然後返回SQL程式碼。

(2)阻塞程序在不斷地執行,所以在程式碼中看到的最後一個操作不一定是導致問題的語句。在本例中最後一條執行語句是導致阻塞的語句。 

查詢視窗

伺服器程序識別符號SPID

執行語句  結果  說明 
 Connection3  57
SELECT  session_id ,
        text
FROM    sys.dm_exec_connections
        CROSS APPLY sys.dm_exec_sql_text
        (most_recent_sql_handle) AS ST
WHERE   session_id IN ( 52, 56 )

 

會話52:
執行的SQL語句:

BEGIN TRAN
UPDATE dbo.myProduct
SET price = price + 1
WHERE id = 1


會話56:
執行的SQL語句:

(@1 tinyint)
SELECT * FROM [dbo].[myProduct] 
WHERE [id][email protected]

★ 4.sys.dm_exec_sessions 檢視

(1)會話建立的時間login_time

(2)特定於會話的客戶端工作站名稱host_name

(3)初始化會話的客戶端程式的名稱program_name

(4)會話所使用的SQL Server登入名login_name

(5)最近一次會話請求的開始時間last_request_start_time

(6)最近一次會話請求的完成時間last_request_end_time 

查詢視窗

伺服器程序識別符號SPID


執行語句 

結果  說明 
 Connection3 57 
SELECT * FROM sys.dm_exec_sessions

★ 5.sys.dm_exec_requests 檢視

(1)識別出阻塞鏈涉及到的會話、爭用的資源、被阻塞會話等待了多長時間

查詢視窗

伺服器程序識別符號SPID


執行語句 

結果  說明 
 Connection3 57 
SELECT * FROM sys.dm_exec_sessions

 

會話56:
(1)被會話52阻塞,blocking_session_id = 52
(2)會話52的開始時間start_time
(3)狀態掛起status = suspended
(4)掛起的命令command=select

★ 6.Lock_TIMEOUT 選項

(1)設定會話等待鎖釋放的超時期限

(2)預設情況下會話不會設定等待鎖釋放的超時期限

(3)設定會話超時期限為5秒, SET Lock_TIMEOUT 5000

(4)鎖定如果超時,不會引發事務回滾

(5)取消會話超時鎖定的設定,SET LOCK_TIMEOUT -1

如果超時,將顯示以下錯誤:

7.KILL <spid> 命令

(1)殺掉會話52,KILL 52

(2)殺掉會話,會引起事務回滾,同時釋放排他鎖

四、隔離級別

1.基本概念:

(1)隔離級別用來做什麼

  a.隔離級別用於決定如何控制併發使用者讀寫資料的操作

(2)寫操作
  a.任何對錶做出修改的語句

  b.使用排他鎖

  c.不能修改讀操作獲得的鎖和鎖的持續時間

(3)讀操作:

  a.任何檢索資料的語句

  b.預設使用共享鎖

  c.使用隔離級別來控制讀操作的處理方式

2.隔離級別的分類

(1)未提交讀 (READ UNCOMMITTED

(2)已提交讀(READ COMMITTED)(預設值)

(3)可重複讀(REPEATABLE READ

(4)可序列化(SERIALIZABLE

(5)快照(SNAPSHOT

(6)已經提交讀快照(READ_COMMITTED_SNAPSHOT

3.隔離級別的設定

(1)設定整個會話的隔離級別

SET TRANSACTION ISOLATION LEVEL <isolation name>;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

(2)用表提示設定查詢的隔離級別

SELECT ... FROM <table> WITH (<isolation name>);
SELECT * FROM dbo.myProduct WITH (READCOMMITTED);


注意:

1.設定會話選項的隔離級別時,隔離級別中的每個單詞之間需要用空格分隔

2.用表提示的隔離級別時,隔離級別中的每個單詞之間不需要用空格分隔

3.表提示的隔離級別有同義詞,如:NOLOCK->READUNCOMMITTED,HOLDLOCK->REPEATABLEREAD

4.隔離級別的嚴格性:1.未提交讀<2.已提交讀<3.可重複讀<4.可序列化

5.隔離級別越高,一致性越高,併發性越低

6.基於快照的隔離級別,SQL Server將提交過的行儲存到tempdb資料庫中,當讀操作發現行的當前版本和它們預期的不一致時,可以立即得到行的以前版本,從而不用請求共享鎖也能取得預期的一致性。

4.隔離級別的行為方式

★ 1.未提交讀 (READ UNCOMMITTED)

開啟兩個查詢視窗,Connetion1,connection2

Step1: 執行Connection1的階段2的SQL 語句,然後執行connection2的SQL語句

Step2: 執行Connection1的階段3的SQL 語句,執行connection2的SQL語句

Step3: 執行Connection1的階段4的SQL 語句,執行connection2的SQL語句

查詢視窗 事務  執行語句
Connetion1 A
--階段2
UPDATE  myProduct
SET     price = price + 1
WHERE   id = 1;
 
SELECT  id ,
        price
FROM    dbo.myProduct
WHERE   id = 1;
 
--階段3
UPDATE  myProduct
SET     price = price + 5
WHERE   id = 1;
 
SELECT  id ,
        price
FROM    dbo.myProduct
WHERE   id = 1;
 
--階段4
COMMIT TRAN
Connection2 B
--在階段2執行之後
SET TRAN ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRAN;
SELECT  id ,
        price
FROM    dbo.myProduct
WHERE   id = 1

COMMIT TRAN;

兩個事務的流程圖:

階段1:Price=10,事務A對myProduct表請求排他鎖

階段2:事務A對myProduct表使用了排他鎖,更新price = price + 1,然後事務A查詢price的價格: price=11。事務B不請求任何鎖,事務B在A更新Price之後進行查詢,price=11

階段3:事務A更新price = price + 5,然後事務A查詢price的價格,price = 16。事務B查詢price的價格: price=16

階段4:事務A釋放排他鎖

階段5:事務A中查詢price的價格:price = 16。事務B查詢price的價格: price=16


大家可以看到事務B有兩種結果,這就是“未提交讀 (READ UNCOMMITTED)”隔離級別的含義:

(1)讀操作可以讀取未提交的修改(也稱為髒讀)。

(2)讀操作不會妨礙寫操作請求排他鎖,其他事務正在進行讀操作時,寫操作可以同時對這些資料進行修改。

(3)事務A進行了多次修改,事務B在不同階段進行查詢時可能會有不同的結果。

★ 2.已提交讀(READ COMMITTED)(預設值)


開啟兩個查詢視窗,Connetion1,connection2

Step1: 執行Connection1的SQL 語句

Step2: 執行Connection2的SQL 語句

執行語句 執行語句
Connetion1 A
UPDATE dbo.myProduct SET price = price + 1 WHERE id=1
SELECT * FROM dbo.myProduct WHERE id =1
Connection2 B
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
SELECT * FROM dbo.myProduct WHERE id = 1

兩個事務的流程圖:

階段1:Price=10,事務A對myProduct表請求排他鎖

階段2:事務A對myProduct表使用了排他鎖,更新price = price + 1,然後事務A查詢price的價格: price=11。然後事務B請求共享鎖進行讀操作,查詢price,

  由於在當前隔離級別下,事務A的排他鎖和事務B的共享鎖存在衝突,所以事務B需要等待事務A釋放排他鎖後才能讀取資料。

階段3:事務A提交事務(COMMIT TRAN)

階段4:事務A提交完事務後,釋放排他鎖

階段5:事務B獲得了共享鎖,進行讀操作,price=11


“已提交讀 (READ UNCOMMITTED)”隔離級別的含義:

(1)必須獲得共享鎖才能進行讀操作,其他事務如果對該資源持有排他鎖,則共享鎖必須等待排他鎖釋放。

(2)讀操作不能讀取未提交的修改,讀操作讀取到的資料是提交過的修改。

(3)讀操作不會在事務持續期間內保留共享鎖,其他事務可以在兩個讀操作之間更改資料資源,讀操作因而可能每次得到不同的取值。這種現象稱為“不可重複讀”

3.可重複讀(REPEATABLE READ)

開啟兩個查詢視窗,Connetion1,connection2

Step1: 執行Connection1的SQL 語句

Step2: 執行Connection2的SQL 語句

執行語句 事務  執行語句
Connetion1 A
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
SELECT * FROM dbo.myProduct WHERE id = 1
Connection2 B
UPDATE dbo.myProduct SET price = price + 1 WHERE id=1

兩個事務的流程圖:

 

階段1:Price=10,事務A對myProduct表請求共享鎖

階段2:事務A對myProduct表使用了共享鎖,事務A查詢price的價格: price=10,事務A一直持有共享鎖直到事務A完成為止。然後事務B請求排他鎖進行寫操作price=price+1,

由於在當前隔離級別下,事務A的共享鎖和事務B請求的排他鎖存在衝突,所以事務B需要等待事務A釋放共享鎖後才能修改資料。

階段3:事務A查詢price, price=10, 說明事務B的更新操作被阻塞了,更新操作沒有被執行。然後事務A提交事務(COMMIT TRAN)

階段4:事務A提交完事務後,釋放共享鎖

階段5:事務B獲得了排他鎖,進行寫操作,price=11


“可重複讀 (REPEATABLE READ)”隔離級別的含義:

(1)必須獲得共享鎖才能進行讀操作,獲得的共享鎖將一直保持直到事務完成之止。

(2)在獲得共享鎖的事務完成之前,沒有其他事務能夠獲得排他鎖修改這一資料資源,這樣可以保證實現可重複的讀取。

(3)兩個事務在第一次讀操作之後都將保留它們獲得的共享鎖,所以任何一個事務都不能獲得為了更新資料而需要的排他鎖,這種情況將會導致死鎖(deadlock),不過卻避免了更新衝突。


★ 4.可序列化(SERIALIZABLE)

開啟兩個查詢視窗,Connetion1,connection2
Step1: 執行Connection1的SQL 語句
Step2: 執行Connection2的SQL 語句

執行語句 事務 
執行語句
Connetion1 A
BEGIN TRANSACTION
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT * FROM dbo.myProduct WHERE id = 1
Connection2 B
INSERT INTO dbo.myProduct(id, price) VALUES (1, 20)

兩個事務的流程圖:

 

階段1:Price=10,事務A對myProduct表請求共享鎖

階段2:事務A對myProduct表使用了共享鎖,事務A查詢id=1的price的價格:1行記錄,price=10,事務A一直持有共享鎖直到事務A完成為止。然後事務B請求排他鎖進行插入操作id=1,price=20,

  由於在當前隔離級別下,事務B試圖增加能夠滿足事務A的讀操作的查詢搜尋條件的新行,所以事務A的共享鎖和事務B請求的排他鎖存在衝突,事務B需要等待事務A釋放共享鎖後才能插入資料。

階段3:事務A查詢出id=1的資料只有1行,說明事務B的插入操作被阻塞了,插入操作沒有被執行。然後事務A提交事務(COMMIT TRAN)

階段4:事務A提交完事務後,釋放共享鎖

階段5:事務B獲得了排他鎖,進行插入操作,插入成功,查詢出id=1的資料有兩條

“可序列化(SERIALIZABLE)”隔離級別的含義:

(1)必須獲得共享鎖才能進行讀操作,獲得的共享鎖將一直保持直到事務完成之止。

(2)在獲得共享鎖的事務完成之前,沒有其他事務能夠獲得排他鎖修改這一資料資源,且當其他事務增加能夠滿足當前事務的讀操作的查詢搜尋條件的新行時,其他事務將會被阻塞,直到當前事務完成然後釋放共享鎖,其他事務才能獲得排他鎖進行插入操作。

(3)事務中的讀操作在任何情況下讀取到的資料是一致的,不會出現幻影行(幻讀)

(4)範圍鎖:讀操作鎖定滿足查詢搜尋條件範圍的鎖

5.隔離級別總結

髒讀:讀取未提交的更改。

不可重複讀:讀操作不會在事務持續期間內保留共享鎖,其他事務可以在兩個讀操作之間更改資料資源,讀操作因而可能每次得到不同的取值。

丟失更新:兩個事務進行讀操作,獲得資源上的共享鎖,讀取完資料後,不再持有資源上的任何鎖,兩個事務都能更新這個值,

    最後進行更新的事務將會覆蓋其他事務做的更改,導致其他事務更改的資料丟失。

幻讀:第一次和第二次讀取到的資料行數不一致。

範圍鎖:讀操作鎖定滿足查詢搜尋條件範圍的鎖

隔離級別 是否讀取未提交的行 是否不可重複讀 是否丟失更新 是否幻讀 共享鎖持續時間 是否持有範圍鎖
未提交讀 READ UNCOMMITTED Y Y Y Y 當前語句 N
已提交讀 READ COMMITTED N Y Y Y 當前語句 N
可重複讀REPEATABLE READ N N N Y 事務開始到事務完成 N
可序列化SERIALZABLE N N N N 事務開始到事務完成 Y

五.死鎖

死鎖是指一種程序之間互相永久阻塞的狀態,可能涉及兩個或更多的程序。

開啟兩個查詢視窗,Connetion1,connection2

Step1: 執行Connection1的SQL 語句

Step2: 執行Connection2的SQL 語句

執行語句 事務  執行語句
Connetion1 A
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRAN
UPDATE dbo.myProduct SET price = price + 1 WHERE id=1
SELECT * FROM dbo.myOrder WHERE id =1
Connection2 B
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRAN
UPDATE dbo.myOrder SET customer = 'ddd' WHERE id = 1
SELECT * FROM dbo.myProduct WHERE id = 1

兩個事務的流程圖:

階段1:Price=10,事務A對myProduct表請求排他鎖。Customer = aaa,事務B對myOrder請求排他鎖

階段2:事務A對myProduct表使用了排他鎖,更新price = price + 1。然後事務B對myOrder表使用了排他鎖,更新customer=ddd。

階段3:事務A查詢myOrder表,對myOrder表請求共享鎖,因為事務A的請求的共享鎖與事務B的排他鎖衝突,所以事務A被阻塞。然後事務B查詢myProduct表,對myProduct表請求共享鎖,因為事務B的請求的共享鎖與事務A的排他鎖衝突,所以事務B被阻塞。

階段4:事務A等待事務B的排他鎖釋放,事務B等待事務A的排他鎖釋放,導致死鎖。事務A和事務B都被阻塞了。

階段5:SQL Server在幾秒之內檢測到死鎖,會選擇一個事務作為死鎖的犧牲品,終止這個事務,並回滾這個事務所做的操作。在這個例子中,事務A被終止,提示資訊:事務(程序 ID 53)與另一個程序被死鎖在 鎖 資源上,並且已被選作死鎖犧牲品。請重新執行該事務。


“死鎖 (Dead Lock)”的一些注意事項:

(1)如果兩個事務沒有設定死鎖優先順序,且兩個事務進行的工作量也差不多一樣時,任何一個事務都有可能被終止。

(2)解除死鎖要付出一定的系統開銷,因為這個過程會涉及撤銷已經執行過的處理。

(3)事務處理的時間時間越長,持有鎖的時間就越長,死鎖的可能性也就越大,應該儘可能保持事務簡短,把邏輯上可以不屬於同一個工作單元的操作移到事務以外。

(4)上面的例子中,事務A和事務B以相反順序訪問資源,所以發生了死鎖。如果兩個事務按同樣的順序來訪問資源,則不會發生這種型別的死鎖。在不改變程式的邏輯情況下,可以通過交換順序來解決死鎖的問題。

關於分析死鎖的問題,可以參考前面寫的關於阻塞的內容。

參考資料:《T-SQL基礎》


作  者:
出  處:http://www.cnblogs.com/jackson0714/
關於作者:專注於微軟平臺的專案開發。如有問題或建議,請多多賜教!
版權宣告:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。
特此宣告:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:如果您覺得文章對您有幫助,可以點選文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!

相關推薦

30分鐘全面解析-SQL事務+隔離級別+阻塞+

 以前總是追求新東西,發現基礎才是最重要的,今年主要的目標是精通SQL查詢和SQL效能優化。  本系列主要是針對T-SQL的總結。 概述: 本篇主要是對SQL中事務和併發的詳細講解。 一、事務 1.什麼是事務 為單個工作單元而執行的一系列操作。如查詢、修改資料、修改資料定義。 2.語法 (

SQL Server 事務隔離級別詳解

完成 sql 事務 create 事務隔離 測試數據 span read type off SQL 事務隔離級別 概述 隔離級別用於決定如果控制並發用戶如何讀寫數據的操作,同時對性能也有一定的影響作用。 步驟 事務隔離級別通過影響讀操作來間接地影響寫操作;可以在回

SQL Server 事務隔離級別

目前 lte log har 獲取 span 單用戶模式 最大 logs 參考文檔: https://docs.microsoft.com/zh-cn/sql/t-sql/statements/set-transaction-isolation-level-transact

Sql Server中的事務事務隔離級別

事務是資料庫進行併發控制非常重要的機制。 1、什麼是事務?   事務是作為單個邏輯工作單元執行的一系列操作,它由一條或者一組語句組成,它們麼全部成功,要麼全部失敗。   舉個例子,比如在12306訂火車票,要麼你訂票成功,餘票顯示就減少一張;要麼你訂票失敗,餘票顯示還是那麼多。不允許出現

【轉】SQL Server 事務隔離級別詳解

SQL 事務隔離級別 概述      隔離級別用於決定如果控制併發使用者如何讀寫資料的操作,同時對效能也有一定的影響作用。 步驟 事務隔離級別通過影響讀操作來間接地影響寫操作;可以在回話級別上設定事務隔離級別也可以在查詢(表級別)級別上設定事務隔離級別。事務隔離級別總共有6個隔離級別:READ UNC

SQL Server 中的事務事務隔離級別以及如何理解髒讀, 未提交讀,不可重複讀和幻讀產生的過程和原因

原本打算寫有關 SSIS Package 中的事務控制過程的,但是發現很多基本的概念還是需要有 SQL Server 事務和事務的隔離級別做基礎鋪墊。所以花了點時間,把 SQL Server 資料庫中的事務概念,ACID 原則,事務中常見的問題,問題造成的原因和事務隔離級別等這些方面的知識好好的整理了一下。

Sql Server 事務隔離級別的檢視及更改

根據自身 Sql Server 的情況來自定義 事務隔離級別,將會更加的滿足需求,或提升效能。例如,對於邏輯簡單的 Sql Server,完全可以使用 read uncommitted 模式,來減少死鎖,減少堵塞, 提升效能和響應。對於此種應用場景應該是蠻多的,但是卻沒有一個全域性設定,你妹呀! 這個功能

一步步走進Sql中的事務事務隔離級別

eight 16px set 隔離 等待 zhang code 數據庫初始 關閉 1.事務定義 事務是按照邏輯執行的一組任務序列,這一組任務序列要麽都執行,要麽都不執行。 事務是優先基於會話配置的的(session),其次是基於全局配置的(global)。 2.事務的

SQL Server 中的事務事務隔離級別以及髒讀

原 本打算寫有關 SSIS Package 中的事務控制過程的,但是發現很多基本的概念還是需要有 事務和事務的隔離級別做基礎鋪墊。所以花了點時間,把 資料庫中的事務概念,ACID 原則,事務中常見的問題,問題造成的原因和事務隔離級別等這些方面的知識好好的整理了一下。 其實有關 SQL Server 中的

資料庫的四種事務隔離級別解析【原創解析

之前在開發中遇到過類似的事務之間的場景,但是並沒有做相關係統學習,今天將這四個事務隔離級別詳細的分析一下,以便在後續開發過程中對事務的理解更透徹。 一、READ-UNCOMMITTED(讀未提交) 1、概念 兩個事務,其中一個事務對資料做的DML操作還未提交,另一個事務能

oracle,mysql,sql server三大數據庫的事務隔離級別查看方法

glob declare ddr 存在 lag har oca flag ali 1:mysql的事務隔離級別查看方法 mysql 最簡單,執行這條語句就行:select @@tx_isolation 詳情: 1.查看當前會話隔離級別 sel

分鐘後,你將真正理解MySQL事務隔離級別

什麼是事務? 事務是一組原子性的SQL操作,所有操作必須全部成功完成,如果其中有任何一個操作因為崩潰或其他原因無法執行,那麼所有的操作都不會被執行。也就是說,事務內的操作,要麼全部執行成功,要麼全部執行失敗。 事務的結束有兩種,當事務中的所有操作全部成功執行時,事務提交。如果其中一個操作失敗,將發生回滾操

mysql的事務隔離級別

too con jpg 級別 tran 開啟 數據行 修改 ges 原文地址:http://www.cnblogs.com/snsdzjlz320/p/5761387.html [Mysql]——通過例子理解事務的4種隔離級別 SQL標準定義了4種隔離級別,包括了一

事務隔離級別的理解

回滾 自己 避免 ron ref blank 提交 範圍 聯系 數據庫事務的隔離級別有4種,由低到高分別為Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事務的並發操作中可能會出現臟讀

mysql 不同事務隔離級別

結果 讀取 般的 lec 不同的 新增 比較 一次 基礎 repeatable read 在同一事務中,同一查詢多次進行時候,由於其他插入操作(insert)的事務提交,導致每次返回不同的結果集。 標準的repeatable read是允許幻讀的,因為這一級別只在讀取過的紀

數據庫事務的四大特性和事務隔離級別

簡單 個數 多個實例 tails ref 感覺 mvc 不能 變換 Reference: [1] http://www.cnblogs.com/fjdingsd/p/5273008.html [2] http://blog.csdn.net/fg2006/article/d

mysql事務隔離級別的關系

美團 enc 自己 ren 問題總結 關系 sql 事務 sql事務 其實操作了這麽久mysql一直也沒有把mysql中事務跟鎖的關系弄得特別清楚。然後搜到美團這篇文章,順便結合一下自己遇到的問題總結一下。 首先事務有四種隔離級別: Refere

mariadb事務隔離級別相關實驗

mariadb mysql 事務 關於SQL的隔離級別SQL標準定義了4類隔離級別,如下所示:1. Read Uncommitted (讀取未提交內容)在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用於實際應用,因為它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之

數據庫事務隔離級別(轉)

事務隔離級別 transacti 隔離級別 二次 設置 新增 重寫 upload strong 1.什麽是事務,事務的特性是什麽? 在數據庫中事務是工作的邏輯單元,一個事務是由一個或多個完成一組的相關行為的SQL語句組成,通過事務機制確保這一組SQL語句所作的操作要麽都成功

數據庫事務的四大特性及事務隔離級別

account nbsp 用戶 rep 相互 轉賬 個數 提示 atomic 概要: 事務的四個特性:原子性、一致性、隔離性、持久性 事務不隔離帶來的問題:臟讀、不可重復讀、虛讀(幻讀) 事務隔離的級別:串行化(111)、可重復讀(110)、讀已提交(100)、讀未提