園子里有很不錯的介紹SQL Server事務隔離的文章,感覺很多都從概念入手介紹的,對那些初學者來說,看得見摸得着的理解才深刻,故不再重復,重點在於實例演示上面。
首先解釋下事務隔離是干什么的,一個事務的隔離級別控制了它怎么樣影響其它事務和被其它事務所影響。
1.READ UNCOMMITTED,會導致臟讀(能讀取其它事務沒有提交的更改)和不可重復讀(事務讀取的數據被其它事務所修改,再次讀取時不一致)
初始化:
CREATE TABLE TranLevel (k int IDENTITY(1,1), val int) INSERT INTO TranLevel(val) values(1) INSERT INTO TranLevel(val) values(2) INSERT INTO TranLevel(val) values(3)
首先執行Query1,再新建查詢立即執行Query2
Query1:
BEGIN TRAN Query1 -- 在事務中修改 UPDATE TranLevel SET val = 9 -- '等待10秒,期間事務2運行' WAITFOR DELAY '00:00:10' -- 不提交修改,回滾事務 ROLLBACK TRAN Query1
Query2:
-- 設置當前會話事務隔離級別為未提交讀 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED BEGIN TRAN Query2 SELECT '事務2開始並發執行,讀取到了事務1修改了但沒有提交的數據,是臟讀' SELECT * FROM Tranlevel SELECT '事務2等待10秒,讓事務1執行完' WAITFOR DELAY '00:00:10' SELECT '兩次讀取的結果不一致,是不可重復讀' SELECT * FROM TranLevel COMMIT TRAN Query2
下面就看看Query2執行的結果是怎樣的:
結果顯而易見,如果將事務隔離級別設置為未提交讀,則會造成臟讀和不可重復讀的問題,在這幾個事務隔離級別中是限制最小的一個,SQL Server分配的資源也最小。
2.READ COMMITTED,提交讀,默認的事務隔離級別,會造成不可重復讀。
初始化:
drop Table tranlevel CREATE TABLE TranLevel (k int IDENTITY(1,1), val int) INSERT INTO TranLevel(val) values(1) INSERT INTO TranLevel(val) values(2) INSERT INTO TranLevel(val) values(3)
Query3:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED BEGIN TRAN Query3 -- 等待10秒,再修改數據 WAITFOR DELAY '00:00:10' UPDATE TranLevel SET val = 10 COMMIT TRAN Query3
Query 4:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED BEGIN TRAN Query4 SELECT '查到的是Query3沒有提交前的數據' SELECT * FROM TranLevel SELECT '讓Query3執行完' WAITFOR DELAY '00:00:10' SELECT '再次查詢,數據就變成Query3執行完后的數據了' SELECT * FROM TranLevel COMMIT TRAN Query4
執行Query3后,新建查詢執行Query4。下面看看Querry4查詢得到的數據。
結果就是Query4中的事務查詢獲得了在Query3提交后的數據,在同一事務中讀取的數據不一致,造成了不可重復讀。
3.REPEATABLE READ,會鎖住那些事務訪問的數據行,但不能防止新行的插入,所以會導致幻讀。
初始化:
drop Table tranlevel CREATE TABLE TranLevel (k int IDENTITY(1,1), val int) INSERT INTO TranLevel(val) values(1) INSERT INTO TranLevel(val) values(2) INSERT INTO TranLevel(val) values(3)
Query5:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ BEGIN TRAN Query5 -- 等待10秒,插入會導致其它事務幻讀的數據 WAITFOR DELAY '00:00:10' INSERT INTO TranLevel(val) values(4) COMMIT TRAN Query5
Query6:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ BEGIN TRAN Query6 SELECT '開始查詢的數據是沒有第4行的' SELECT * from TranLevel WAITFOR DELAY '00:00:10' SELECT '比剛才查詢到的數據多了一行,幻讀' SELECT * from TranLevel COMMIT TRAN Query6
執行Query5后,新建查詢執行Query6。下面看看Querry6查詢得到的數據:
可以看到,即使設置為可重復讀,仍然會導致在同一事務中查詢的數據不一致的情況,即幻讀。
4.SHNAPSHOT 和 SERIALIZABLE 能解決臟讀、不可重復讀、幻讀的問題,就沒有必要再寫實例來說明了。SHNAPSHOT級別對並發情況采用樂觀處理,如果兩個事務同時修改了一行數據,則后嘗試修改的事務會爆沖突,但如果修改的是不同行,則不會有這個問題。如果不理解的朋友可以參考下面這個鏈接:
http://blogs.msdn.com/b/craigfr/archive/2007/05/16/serializable-vs-snapshot-isolation-level.aspx
實例sql語句下載地址:http://files.cnblogs.com/ProJKY/TranLevel.zip