1. 程式人生 > >innodb事務隔離級別

innodb事務隔離級別

事務隔離級別

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》第二版