MySQL InnoDB中的事務隔離級別和鎖的關係

別嚇本抱抱發表於2020-12-15

事務中的加鎖方式

1、事務的四種隔離級別

隔離級別髒讀(Dirty Read)不可重複讀(NonRepeatable Read)幻讀(Phantom Read)
未提交讀(Read uncommitted)可能可能可能
已提交讀(Read committed)不可能可能可能
可重複讀(Repeatable read)不可能不可能可能
序列化(Serializable )不可能不可能不可能

1.讀未提交
事務1還沒提交,事務2就能讀到事務1修改的內容
2.讀已提交
讀一個事務提交後的資料。
但是事務2在事務1提交前和提交後,讀的資料是不一樣的。e.g“不可重複讀”
事務1查詢,但是事務2又插入新的記錄,原先事務1再次查詢時,會把後來插入的記錄也讀出來。e.g“幻讀”
3.可重複讀
MySQL幫我們解決掉了幻讀問題。
4.序列化
只允許同一條記錄進行修改。

在這裡插入圖片描述

2、MySQL中鎖的種類

MySQL中鎖的種類很多,有常見的表鎖和行鎖,也有新加入的Metadata Lock等等,表鎖是對一整張表加鎖,雖然可分為讀鎖和寫鎖,但畢竟是鎖住整張表,會導致併發能力下降,一般是做ddl處理時使用。

行鎖則是鎖住資料行,這種加鎖方法比較複雜,但是由於只鎖住有限的資料,對於其它資料不加限制,所以併發能力強,MySQL一般都是用行鎖來處理併發事務。這裡主要討論的也就是行鎖。

1)、Read Committed(讀取提交內容)

資料的讀取都是不加鎖的,但是資料的寫入、修改和刪除是需要加鎖的。

2)、Repeatable Read(可重讀)

這是MySQL中InnoDB預設的隔離級別。我們姑且分“讀”和“寫”兩個模組來講解。

a、讀

####不可重複讀和幻讀的區別####

很多人容易搞混不可重複讀和幻讀,確實這兩者有些相似。但不可重複讀重點在於update和delete,而幻讀的重點在於insert。

如果使用鎖機制來實現這兩種隔離級別,在可重複讀中,該sql第一次讀取到資料後,就將這些資料加鎖,其它事務無法修改這些資料,就可以實現可重複讀了。但這種方法卻無法鎖住insert的資料,所以當事務A先前讀取了資料,或者修改了全部資料,事務B還是可以insert資料提交,這時事務A就會發現莫名其妙多了一條之前沒有的資料,這就是幻讀,不能通過行鎖來避免。需要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼做可以有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的降低資料庫的併發能力。

所以說不可重複讀和幻讀最大的區別,就在於如何通過鎖機制來解決他們產生的問題。

上文說的,是使用悲觀鎖機制來處理這兩種問題,但是MySQL、ORACLE、PostgreSQL等成熟的資料庫,出於效能考慮,都是使用了以樂觀鎖為理論基礎的MVCC(多版本併發控制)來避免這兩種問題。

讀可提交和可重複讀的實現原理

每行資料通過事務ID來識別
在這裡插入圖片描述
在這裡插入圖片描述每次修改會用這種方式記錄,最新版本用連結連起來
在這裡插入圖片描述事務ID為200時,就能夠讀到這行資料為1,4,1,1,a3
但是當事務ID為300時,沒有一條ID符合當前ID,就要用到ReadView
在這裡插入圖片描述
在這裡插入圖片描述
select, readview[100,200]
在select的時候,裡面存的是還沒有提交的事務

讀已提交,每次讀會產生一個readview,readview裡面存的是活躍的記錄,查詢時會排除這些記錄

在這裡插入圖片描述可重複讀,每次讀的時候,使用的都是第一次查詢時產生的readview

1.select, readview[100,200]
// b commit
2.select, readview[100,200]

實現方式都是通過版本鏈和readview,
區別在於readview的產生時間
讀已提交,是在每次select,都會產生一個readview。
每次查詢開始,都把現在沒有提交的事務,都存在readview裡面。
比方,第二次查詢ID200已經提交,那麼readview[100],減少了。
可重複讀,readview只會在第一次讀的時候產生。之後使用的readview都是第一次產生的readview
讀鎖、寫鎖

for update
加了寫鎖,但是還能夠select查詢
鎖必須在事務內部使用
事務結束之後,鎖也會被釋放

行鎖

在read commited下

  • 查詢使用主鍵
    總結:查詢使用的是主鍵時,只需要在主鍵值對應的那一個條資料加鎖即可。
  • 查詢使用唯一主鍵
    總結:查詢使用的是唯一索引時,只需要對查詢值所對應的唯一索引記錄項和對應的聚集索引上的項加鎖即可。
  • 查詢使用的普通索引
    在這裡插入圖片描述
    總結:查詢使用的是普通索引時,會對滿足條件的索引記錄都加上鎖,同時對這些索引記錄對應的聚集索引上的項也加鎖。
  • 查詢沒有用到索引
    在這裡插入圖片描述
    總結:查詢的時候沒有走索引,也只會對滿足條件的記錄加鎖。

在repeatble read下

  • 查詢使用主鍵
  • 查詢使用唯一索引
    和RC級別一樣
  • 查詢使用普通索引
    在這裡插入圖片描述
    總結: REPEATABLE READ級別可以解決幻讀,解決的方式就是加了GAP鎖。
  • 查詢沒有用到索引
    在這裡插入圖片描述
    總結:查詢的時候沒有走索引,會對錶中所有的記錄以及間隙加鎖。

相關文章