概述
今天主要分享下MySQL事務隔離級別的實現原理,因為只有InnoDB支持事務,所以這里的事務隔離級別是指InnoDB下的事務隔離級別。
隔離級別
-
讀未提交:一個事務可以讀取到另一個事務未提交的修改。這會帶來臟讀,幻讀,不可重復讀問題
-
讀已提交:一個事務只能讀取另一個事務已經提交的修改。其避免了臟讀,仍然存在不可以重復讀和幻讀問題
-
可重復讀:同一個事務中多次讀取相同的數據返回的結果是一樣的。其避免了臟讀和不可重復讀問題,但是幻讀依然存在
-
串行化:事務串行之行。避免了以上所有問題
以上是SQL-92標准中定義的四種隔離級別。在MySQL中,默認的隔離級別是REPEATABLE-READ(可重復讀),並且解決了幻讀問題。
注:不可重復讀重點在於Update和delete,而幻讀的重點在於insert。
MVCC
MVCC的全稱是多版本並發控制。MVCC使得InnoDB的事務隔離級別下執行一致性讀操作有了保證。
簡單說就是為了查詢一些正在被另一個事務更新的行,並且可以看到它們被更新之前的值。這是一個用來增強並發性的強大技術,可以使得查詢不用等待另一個事務釋放鎖。
如下圖所示:
MVCC會給每一行增加三個字段,分別是:DB-TRX-ID、DB-ROLL-PTR、DB-ROW-ID
增刪查改
在InnoDB中,給每行增加兩個隱藏字段來實現MVCC,一個用來記錄數據行的創建時間,另一個用來記錄行的過期時間。
在實際操作中,存儲的並不是時間,而是事務版本號,每開啟一個新事務,事務的版本號就會遞增。所以增刪改查中對版本號的作用如下:
select:
讀取創建版本小於或等於當前事務版本號,並且刪除版本為空或大於當前事務版本的記錄。這樣可以保證在讀取之前記錄都是存在的
insert:
將當前事務的版本號保存至行的創建版本號
update
新插入一行,並以當前事務版本號作為新行的創建版本號,同時將原記錄行的刪除版本號設置為當前事務版本號
delete
將當前事務版本號保存至行的刪除版本號
快照讀和當前讀
-
快照讀:讀取的是快照版本,也就是歷史版本
-
當前讀:讀取的是最新版版
普通的 select 就是快照讀,而 update,delete,insert,select...LOCK In SHARE MODE,SELECT...for update 就是當前讀
一致性非鎖定讀和鎖定讀
首先看看下面的圖:
1、鎖定讀
在一個事務中,標准的SELECT語句是不會加鎖,但是有兩種情況例外。
-
SELECT ... LOCK IN SHARE MODE
-
SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE:給記錄假設共享鎖,這樣其他事務職能讀不能修改,直到當前事務提交
SELECT ... FOR UPDATE:給索引記錄加鎖,這種情況跟UPDATE的加鎖情況是一樣的
2、一致性非鎖定讀
consistent read(一致性讀),InnoDB用多版本來提供查詢數據庫在某個時間點的快照。
如果隔離級別是REPEATABLE READ,那么在同一個事務中的所有一致性讀都讀的是事務中第一個的讀讀到的快照;如果是READ COMMITTED,那么一個事務中的每一個一致性讀都會讀到它自己刷新的快照版本。
consistent read(一致性讀)是READ COMMITTED和REPEATABLE READ隔離級別下普通SELECT語句默認的模式。一致性讀不會給它鎖訪問的表加任何形式的鎖,因此其他事務可以同時並發的修改它們
鎖
-
Record Locks(記錄鎖):在索引記錄上加鎖
-
Gap Locks(間隙鎖):在索引記錄之間加鎖,或者在第一個索引記錄之前加鎖,或者在最后一個索引記錄之后加鎖
-
Next-Key Locks:在索引記錄上加鎖,並且在索引記錄之前的間隙加鎖。相當於Record Locks與Gap Locks的一個結合
假如一個索引包含以下幾個值:10,11,13,20.那么這個索引的next-key鎖將會覆蓋以下區間:
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)
總結
在默認的隔離級別中,普通的SELECT用的是一致性讀不加鎖。而對於鎖定讀,UPDATE和DELETE,則需要加鎖,至於加什么鎖是有不同情況的。
如果對一個唯一索引使用了唯一的檢索條件,那么只需要鎖定相應的索引記錄就好;如果是沒有使用唯一索引作為檢索條件,或者用到了索引范圍掃描,那么將會使用間隙鎖或者next-key鎖來以此阻塞其他會話向這個范圍內的間隙插入數據
利用MVCC實現一致性非鎖定讀,保證在同一個事務中多次讀取相同的數據返回的結果是一樣的,解決了不可重復讀問題.
利用Gap Locks和Next-key可以阻止其他事務在鎖定區間內插入數據,解決了幻讀問題.
總之,MySQL的默認隔離級別的實現依賴於MVCC和鎖,准確點說就是一致性讀和鎖。