SQL鎖機制和事務隔離級別

iSQlServer發表於2009-03-09

NOLOCKREADPAST的區別。

1.       開啟一個事務執行插入資料的操作。

BEGIN TRAN t

INSERT INTO Customer

SELECT 'a','a'

2.       執行一條查詢語句。

SELECT * FROM Customer WITH (NOLOCK)

結果中顯示”a””a”。當1中事務回滾後,那麼a將成為髒資料。(:1中的事務未提交) NOLOCK表明沒有對資料表新增共享鎖以阻止其它事務對資料表資料的修改。

SELECT * FROM Customer

這條語句將一直死鎖,直到排他鎖解除或者鎖超時為止。(:設定鎖超時SET LOCK_TIMEOUT 1800)

SELECT * FROM Customer WITH (READPAST)

這條語句將顯示a未提交前的狀態,但不鎖定整個表。這個提示指明資料庫引擎返回結果時忽略加鎖的行或資料頁。

3.       執行一條插入語句。

BEGIN TRAN t

INSERT INTO Customer

SELECT 'b','b'

COMMIT TRAN t

這個時候,即使步驟1的事務回滾,那麼a這條資料將丟失,而b繼續插入資料庫中。 

 

NOLOCK

1. 執行如下語句。

BEGIN TRAN ttt

SELECT * FROM Customer WITH (NOLOCK)

WAITFOR delay '00:00:20'

COMMIT TRAN ttt

注:NOLOCK不加任何鎖,可以增刪查改而不鎖定。

INSERT INTO Customer SELECT 'a','b' –不鎖定

DELETE Customer where ID=1 不鎖定

SELECT * FROM Customer 不鎖定

UPDATE Customer SET Title='aa' WHERE ID=1 不鎖定

 

ROWLOCK

1.       執行一條帶行鎖的查詢語句。

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ -- (必須)

BEGIN TRAN ttt

SELECT * FROM Customer WITH (ROWLOCK) WHERE ID=17

WAITFOR delay '00:00:20'

COMMIT TRAN ttt

注:在刪除和更新正在查詢的資料時,會鎖定資料。對其他未查詢的行和增加,查詢資料無影響。

INSERT INTO Customer SELECT 'a','b' –不等待

 

DELETE Customer where ID=17 –等待

DELETE Customer where ID<>17 –不等待

 

SELECT * FROM Customer –不等待

 

UPDATE Customer SET Title='aa' WHERE ID=17–等待

UPDATE Customer SET Title='aa' WHERE ID<>17–不等待

 

 

HOLDLOCKTABLOCKTABLOCKX

1.       執行HOLDLOCK

BEGIN TRAN ttt

SELECT * FROM Customer WITH (HOLDLOCK)

WAITFOR delay '00:00:10'

COMMIT TRAN ttt

注:其他事務可以讀取表,但不能更新刪除  

update Customer set Title='aa' 要等待10秒中。

SELECT * FROM Customer —不需要等待

 

2.       執行TABLOCKX

BEGIN TRAN ttt

SELECT * FROM Customer WITH (TABLOCKX)

WAITFOR delay '00:00:10'

COMMIT TRAN ttt

注:其他事務不能讀取表,更新和刪除

update Customer set Title='aa' 要等待10秒中。

SELECT * FROM Customer —要等待10秒中。

 

3. 執行TABLOCK

BEGIN TRAN ttt

SELECT * FROM Customer WITH (TABLOCK)

WAITFOR delay '00:00:10'

COMMIT TRAN ttt

注:其他事務可以讀取表,但不能更新刪除  

update Customer set Title='aa' 要等待10秒中。

SELECT * FROM Customer —不需要等待

 

UDPLOCK

1.       A連線中執行。

BEGIN TRAN ttt

SELECT * FROM Customer WITH (UPDLOCK)

WAITFOR delay '00:00:10'

COMMIT TRAN ttt

2.       在其他連線中執行。

update Customer set Title='aa' where ID=1—要等10

SELECT * FROM Customer –不用等

insert into Customer select 'a','b'不用等

注:對於UDPLOCK鎖,只對更新資料鎖定。

 

注:使用這些選項將使系統忽略原先在SET語句設定的事務隔離級別(SET Transaction Isolation Level)

 

 

事務隔離級別

 

髒讀:READ UNCOMMITTED

髒讀就是指當一個事務正在訪問資料,並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。因為這個資料是還沒有提交的資料,那麼另外一個事務讀到的這個資料是髒資料,依據髒資料所做的操作可能是不正確的。

1.       A連線中執行。

BEGIN TRAN t

INSERT INTO Customer

SELECT '123','123'

WAITFOR delay '00:00:20'

COMMIT TRAN t

2.       B連線中執行。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT * FROM Customer

這個時候,未提交的資料會’123’會顯示出來,當A事務回滾時就導致了髒資料。相當於(NOLOCK)

 

提交讀:READ COMMITTED

1.       A連線中執行。

BEGIN TRAN t

INSERT INTO Customer

SELECT '123','123'

WAITFOR delay '00:00:20'

COMMIT TRAN t

2.       B連線中執行。

SET TRANSACTION ISOLATION LEVEL READ COMMITTED

SELECT * FROM Customer

這個時候,未提交的資料會’123’不會顯示出來,當A事務提交以後B中才能讀取到資料。避免了髒讀。

 

不可重複讀:REPEATABLE READ

不可重複讀是指在一個事務內,多次讀同一資料。在這個事務還沒有結束時,另外一個 事務也訪問該同一資料。那麼,在第一個事務中的兩次讀資料之間,由於第二個事務的修改,那麼第一個事務兩次讀到的資料可能是不一樣的。這樣就發生了在一個 事務內兩次讀到的資料是不一樣的,因此稱為是不可重複讀。

例如:

1.       A連線中執行如下語句。

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

BEGIN TRAN ttt

SELECT * FROM Customer WHERE ID=17

WAITFOR delay '00:00:30'

SELECT * FROM Customer WHERE ID=17

COMMIT TRAN ttt

2.       B連線中執行如下語句,而且要在第一個事物的三十秒等待內。

UPDATE Customer SET Title='d' WHERE ID=17

這個時候,此連線將鎖住不能執行,一直等到A連線結束為止。而且A連線中兩次讀取到的資料相同,不受B連線干擾。

注,對於Read CommittedRead UnCommitted情況下,B連線不會鎖住,等到A連線執行完以後,兩條查詢語句結果不同,即第二條查詢的Title變成了d

 

序列化讀:SERIALIZABLE

1.       A連線中執行。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN t

UPDATE Customer SET Title='111'

WAITFOR delay '00:00:20'

COMMIT TRAN t

2. B連線中執行,並且要在A執行後的20秒內。

BEGIN TRAN tt

INSERT INTO Customer

SELECT '2','2'

COMMIT TRAN tt

A連線的事務提交之前,B連線無法插入資料到表中,這就避免了幻覺讀。

 

注:幻覺讀是指當事務不是獨立執行時發生的一種現象,例如 第一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好像發生了幻覺一樣。

 

 

共享鎖

共享鎖(S 鎖)允許併發事務在封閉式併發控制(請參閱併發控制的型別)下讀取 (SELECT) 資源。資源上存在共享鎖(S 鎖)時,任何其他事務都不能修改資料。讀取操作一完成,就立即釋放資源上的共享鎖(S 鎖),除非將事務隔離級別設定為可重複讀或更高階別,或者在事務持續時間內用鎖定提示保留共享鎖(S 鎖)。

 

更新鎖

更新鎖(U 鎖)可以防止常見的死鎖。在可重複讀或可序列化事務中,此事務讀取資料 [獲取資源(頁或行)的共享鎖(S 鎖)],然後修改資料 [此操作要求鎖轉換為排他鎖(X 鎖)]。如果兩個事務獲得了資源上的共享模式鎖,然後試圖同時更新資料,則一個事務嘗試將鎖轉換為排他鎖(X 鎖)。共享模式到排他鎖的轉換必須等待一段時間,因為一個事務的排他鎖與其他事務的共享模式鎖不相容;發生鎖等待。第二個事務試圖獲取排他鎖(X 鎖)以進行更新。由於兩個事務都要轉換為排他鎖(X 鎖),並且每個事務都等待另一個事務釋放共享模式鎖,因此發生死鎖。

 

若要避免這種潛在的死鎖問題,請使用更新鎖(U 鎖)。一次只有一個事務可以獲得資源的更新鎖(U 鎖)。如果事務修改資源,則更新鎖(U 鎖)轉換為排他鎖(X 鎖)。

 

排他鎖

排他鎖(X 鎖)可以防止併發事務對資源進行訪問。使用排他鎖(X 鎖)時,任何其他事務都無法修改資料;僅在使用 NOLOCK 提示或未提交讀隔離級別時才會進行讀取操作。

 

資料修改語句(如 INSERTUPDATE DELETE)合併了修改和讀取操作。語句在執行所需的修改操作之前首先執行讀取操作以獲取資料。因此,資料修改語句通常請求共享鎖和排他鎖。例如,UPDATE 語句可能根據與一個表的聯接修改另一個表中的行。在此情況下,除了請求更新行上的排他鎖之外,UPDATE 語句還將請求在聯接表中讀取的行上的共享鎖。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16436858/viewspace-564920/,如需轉載,請註明出處,否則將追究法律責任。

相關文章