轉載於:http://blog.csdn.net/wudongxu/article/details/8623610
SQL標准定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的並發處理,並擁有更低的系統開銷。
Read Uncommitted(讀取未提交內容)
在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用於實際應用,因為它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之為髒讀(Dirty Read)。
Read Committed(讀取提交內容)
這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別也支持所謂的不可重復讀(Nonrepeatable Read),因為同一事務的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結果。
Repeatable Read(可重讀)
這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在並發讀取數據時,會看到同樣的數據行。不過理論上,這會導致另一個棘手的問題:幻讀(Phantom Read)。簡單的說,幻讀指當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本並發控制(MVCC,Multiversion Concurrency Control 間隙鎖)機制解決了該問題。注:其實多版本只是解決不可重復讀問題,而加上間隙鎖(也就是它這裡所謂的並發控制)才解決了幻讀問題。
Serializable(可串行化)
這是最高的隔離級別,它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
髒讀(Drity Read):某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由於某些原因,前一個RollBack了操作,則後一個事務所讀取的數據就會是不正確的。
不可重復讀(Non-repeatableread):在一個事務的兩次查詢之中數據不一致,這可能是兩次查詢過程中間插入了一個事務更新了原有的數據。
幻讀(Phantom Read):當對某行執行插入或刪除操作,而該行屬於某個事務正在讀取的行的范圍時,會發生幻像讀問題。事務第一次讀的行范圍顯示出其中一行已不復存在於第二次讀或後續讀中,因為該行已被其它事務刪除。同樣,由於其它事務的插入操作,事務的第二次或後續讀顯示有一行已不存在於原始讀中。幻讀其實也應該算是一種不可重復讀現象,只是它只是相對於insert和delete操作,而上面的不可重復讀現象但注重的是update操作。這裡這樣稱呼的原因是insert的新的row是沒有版本信息的,它要通過一個范圍來確定。
注:這裡的客戶端也是一個事務。
set sessiontransaction isolation level read uncommitted;
set autocommit=0;
髒讀的演示:
客戶端1
圖1
客戶端2
圖2
通過上面兩張圖可以清楚的看到當tx_isolation=readuncommitted的時候,當一個事務(事務1)修改了數據但並沒有提交的時候,另外的事務(事務2)是可以訪問到該修改的數據。而此時如果前一個事務又取消了之前的修改(rollback)的時候,那麼事務2得到的數據就是一個“髒”數據。下面我們看一下read committed是否有會這種情況。
客戶端1
圖3
圖4
通過圖3可以看到即客戶端2 update了(但還沒commit),此時客戶端1讀到的還是之前的數據,當客戶端2真正的commit之後,客戶端1才能讀到更新後的數據。另外通過圖3我們同時可以看到另一個現象,不可重復讀,即在一個事務內(客戶端1)兩次讀取的數據不一致。下面我們看一下在Repeatable Read級別下是否有該現象。
Repeatable Read可重復讀
圖5
圖6
通過圖5可以看到即使客戶端2commit之後但客戶端1還沒commit的話,那麼在該事務內的任何時候,訪問同一條記錄的結果都是一樣的。所以repeatable read不存在不可重復讀問題。
幻讀:其實跟不可重復讀差不多,只是幻讀指的是行記錄數(一個范圍),而不可重復讀相對的是一條記錄。如在事務1裡第一次讀取這個范圍的記錄數為10條,但另一個事務刪除了這個范圍內的某一條記錄,這時就會導致事務2的再次讀取與第一次讀取的結果不一致。Innodb通過MCVV+間隙鎖解決了這個問題。所以對於innodb在repeatable read等級上也不會出現幻讀。當前串行化更不會出現上面的問題,因為
事務串行化
圖7
圖8
注:上面的注釋序號表示操作或結果的出現順序。事務1先於事務2執行。通過圖7,8可以看到當事務1 select了表tx_test之後,事務2的update被阻塞了(因為存在一個共享鎖),只有當事務1 commit之後update才真正的被執行,同時此時tx_test又被事務2所占有(排它鎖),所以客戶1(事務3) select也被阻塞了,只有在
事務2 commit之後才得以執行。
MVCC是為了減少加鎖而引入了,從而來提高並發性。MVCC只工作在repeatable read和read commit兩個隔離級別。而read uncommitted則是每次只管讀最新的版本的數據行,serializable則會對每個讀取操作加鎖,所以也不需要MVCC。
上面就是innodb支持的4種隔離級別,以及它們存在的問題。同時我們通過實驗驗證了這些問題。
參考資料:
《高性能mysql》第二版