標籤:

淺談事務隔離級別

學資料庫的時候,老師就叫我們背事務隔離級別的概念,默寫出相應可能會出現的問題。那麼究竟在哪些場景下會因為隔離級別的不同而出現這些問題呢。

事務隔離性

事務的ACID大家自然都背得很熟了,那麼隔離性就是定義了資料庫系統中一個操作的結果在何時以何種方式對其他並發操作可見。也就是說,資料庫多個事務在不同情況下,是區別並發執行串列執行的。正因為如此資料庫設置了鎖的概念,來確保並發控制機制能夠有效運行下去。

所以談論到的隔離級別,通常也與鎖的設置方式有關。

隔離級別

為了獲取更高的隔離等級,資料庫系統的鎖機制或者多版本並發控制機制都會影響並發。很多資料庫定義了不同的事務隔離等級來控制其鎖的程度。根據標準定義,我們都知道有:未提交讀 read uncommited, 提交讀 read commited, 可重複讀 repeatable read, 可串列化 Serializable。

雖然中文很拗口,但是這些隔離等級的名字其實是解決上一個隔離等級所出現問題而提出的解決方案(除了 read uncommited)。

他們的區別之一在於鎖對於R/W事務上設置的不同,當然最高隔離級別也存在對錶鎖的設置。

  • read uncommited: 不對讀事務設置鎖;對寫事務設置行級共享鎖
  • read commited: 對讀事務設置行級共享鎖,讀完就釋放;對寫事務設置行級互斥鎖,直到事務結束才釋放
  • repeatable read: 對讀事務設置行級共享鎖,直到事務結束才釋放;對寫事務設置行級互斥鎖,直到事務結束才釋放
  • Serializable: 所有事務串列執行,讀事務設置表級共享鎖;寫事務設置表級互斥鎖

可以看出來,隔離級別的提高,其實也是鎖的嚴格程度的提高。要知道,相同條件下,鎖越多,越嚴格那麼性能也就越低。

除了臟讀以外,其他因為隔離級別導致的問題,都會出現在當前隔離級別與比當前隔離級別要弱的隔離級別中

共享鎖:多個事務對於加了鎖的數據,只能讀,不能寫;

互斥鎖:排他鎖允許當前事物刪除或更新一行記錄,其他事務不能操作該數據。

臟讀

只會出現在read uncommited隔離等級的問題,因為read uncommited不對讀事務設置鎖,並且對寫事務只設置行級共享鎖

示意圖如下:

-T1--T2--R1--W1--R2--T2--T1-

T2事務全程發生在T1事務的進行時,因為沒有對記錄設置行級互斥鎖,所以在W1寫操作進行前後,可以隨時讀取該記錄,導致了R1和R2讀到的不一樣。非常危險,這就是臟讀。

不可重複讀

因為讀事務在讀完一條數據以後(沒有結束事務),就立馬釋放了行級共享鎖,歸根結底,就是這一原因導致了不可重複讀的發生。

-T1--R1--T2--W1--T2--R2-

R1讀完就釋放了鎖,但是T1事務未結束,這時候另外一個T2事務開始了,在T2事務結束前,第一個事務都不能對這條記錄進行加鎖了(想想為什麼),所以R2要在T2結束後進行。這時候R2讀到的數據與R1又不一樣了。這就是不可重複讀。

幻讀

我們都針對某一記錄讀操作與寫操作添加鎖,並且保證了事務結束時才釋放鎖了。這是還會有問題嗎?

我們一直只針對某一條記錄來進行操作,這時候要是表內又新來了一條數據呢,它可不受任何讀寫鎖的約定呀。

示意圖:

-T1--R1--T2--C--T2--R2--T1-

R1、R2在這裡表示了讀整個表的操作,C代表了在T2事務期間,新增的一條記錄,你會發現在事務T1內的兩次讀(R1,R2),得到的數據不一樣。

因為R1隻對原有的N條記錄加了鎖,而沒對新增的記錄加鎖,這就導致T2事務可以與T1事務並發執行,最終導致了R2與R1讀到的記錄不一致。

所以我們可以提供事務隔離等級來防止這種情況出現,但是在也就是意味著,事務之間再無並發執行可言了。


推薦閱讀:

關於高並發解決問題的一點總結
資料庫面試題(開發者必看)
Mysql資料庫主從心得整理
關係型資料庫 RDBMS 的舊與新 -- 談談 NewSQL
SequoiaDB擴容介紹與最佳實踐

TAG:資料庫 |