MVCC多版本控制機制:MySQL事務時光機!
多事務操作同一行數(shù)據(jù)的時候,就會出現(xiàn)各種并發(fā)問題,mysql通過四種隔離級別來解決這些問題,
讀未提交隔離級別是最寬松的,基本沒有做隔離,所以實現(xiàn)起來很簡單;
讀提交隔離級別是每次執(zhí)行語句(包括查詢和更新語句)的時候都會生成一個一致性視圖,從而保證當前事務可以看到其他事務提交后的數(shù)據(jù);
可重復讀隔離級別的實現(xiàn)是每個事務在開啟的時候都會生成一個一致性視圖,當其他事務有提交后也不會影響當前事務中的數(shù)據(jù),要保證這一點mysql是通過多版本控制機制MVCC來實現(xiàn)的。
可串行化隔離級別的隔離級別比較高,是通過加鎖來實現(xiàn),所以mysql有一套鎖機制。
讀提交和可重復讀隔離級別都是依賴于MVCC多版本控制機制實現(xiàn),今天我們就來討論mysql中的MVCC多版本控制機制
1MVCC多版本控制機制
MVCC機制是通過read-view機制與undo log版本鏈比對機制,使得不同的事務會根據(jù)數(shù)據(jù)版本鏈對比規(guī)則讀取同一條數(shù)據(jù)在版本鏈上的不同版本數(shù)據(jù)。
undo log版本鏈
事務在開啟的時候首先會申請一個事務id:ransaction id
事務對某行數(shù)據(jù)做修改操作的時候,Mysql會保留修改前的數(shù)據(jù)undo回滾日志,并且把事務id:ransaction id賦值給版本記錄中的字段trx_id。
把這些undo log日志串聯(lián)起來形成一個歷史記錄版本鏈,如圖
圖片
注意這里的版本記錄不是真實物理存在的,真實物理存在只有最新的一條記錄,其他歷史記錄都是通過回滾日志推導出來的。
read-view機制
可重復讀隔離級別和讀提交隔離級別是通過生成一個一致性視圖來實現(xiàn),這個一致性視圖就是read-view。
一致性視圖是什么
圖片
一個事務啟動的時候,innodb會為這個事務構(gòu)造一個數(shù)組,用來保存這個事務的啟動瞬間正在活躍的所有事務id?!盎钴S”指的是啟動了,但是沒提交。
數(shù)組里面id最小的值即為低水位,最大的值+1記為高水位,這便是一致性視圖。
每個事務在做查詢的時候會根據(jù)一致性視圖的可見性規(guī)則去undo log版本鏈中推導對應的數(shù)據(jù)。
一致性視圖的可見性規(guī)則
- 如果當前事務id落在綠色部分,表示這個版本是已提交的事務或者是當前事務自己生成的,這個數(shù)據(jù)是可見的;
- 如果當前事務id落在紅色部分,表示這個版本是由將來啟動的事務生成的,是肯定不可見的;
- 如果當前事務id落在黃色部分,那就包括兩種情況:
a. 若 row trx_id在數(shù)組中,表示這個版本是由還沒提交的事務生成的,不可見;
b. 若 row trx_id不在數(shù)組中,表示這個版本是已經(jīng)提交了的事務生成的,可見。
2案例
圖片
圖中事務A查詢的i是什么?我們先來分析一下。
按照從上到下事務開啟的順序,每個事務對應的一致性視圖如下:
事務A的一致性視圖數(shù)組[11]
事務B的一致性視圖數(shù)組[11,12]
事務C的一致性視圖數(shù)組[11,12,13]
事務A在查詢的那個時刻,undo log版本鏈是:
{trx_id=11,id=1,i=10,roll_pointer=0}>>>{trx_id=13,id=1,i=11,roll_pointer=1}>>>{trx_id=12,id=1,i=12,roll_pointer=2}
“{}” 代表的是版本記錄
“>>>” 代表的是回滾日志undo log
事務A在查詢的時候,事務B和事務C屬于未來事務,對事務A是不可見的。因此事務A查詢的數(shù)據(jù)是通過最新的數(shù)據(jù)記錄根據(jù)undo log不斷向前回滾才得到的數(shù)據(jù):i=10。
再看一個案例
圖片
事務A查詢1結(jié)果是什么?
事務A查詢2結(jié)果是什么?
由一致性視圖可見性規(guī)則分析,對事務A來說,事務B是未來事務,對事務A是不可見的,因此查詢結(jié)果i=10。
查詢2的結(jié)果i=12,為什么呢?先來看看兩個概念
在可重復讀隔離級別中這種通過回滾日志找到對應版本記錄的讀取方式就是一致性讀
而不需要回滾,永遠只需要讀取最新版本記錄的方式就是當前讀
事務中如果有更新語句的話,更新語句都是以當前讀的方式讀取到版本記錄中最新數(shù)據(jù),然后再進行更新操作,因此上圖中的查詢結(jié)果為i=12。
下面兩種查詢方式也是當前讀:
select k from t where id=1 lock in share mode;
select k from t where id=1 for update;
以上便是MVCC機制,按照其規(guī)則,這種機制只有在可重復讀隔離級別和讀提交隔離級別下才會有。