1. MVCC的基本概念
1.1 三種數(shù)據(jù)庫并發(fā)場景
讀-讀:不存在任何問題,也不需要并發(fā)控制
讀-寫:有線程安全問題,可能會造成事務隔離性問題,可能遇到臟讀,幻讀,不可重復讀
寫-寫:有線程安全問題,可能會存在更新丟失問題
1.2 什么是MVCC
MVCC,全稱Multi-Version Concurrency Control,即多版本并發(fā)控制,是樂觀鎖的一種實現(xiàn)方式,可以做到讀不加鎖,讀寫不沖突,解決讀-寫沖突的無鎖并發(fā)控制。
注意:
????????MVCC?只在?Read?Commited?和 Repeatable?Read?兩種隔離級別下工作。
1.3 快照讀與當前讀的解釋
快照讀:
????????簡單的select操作,不需要加鎖,基于MVCC和undo log來實現(xiàn)的,讀取的是記錄的可見版本(有可能是歷史版本)。
當前讀:
????????特殊的讀操作,需要加鎖,是悲觀鎖的實現(xiàn),讀取的是記錄的最新版本,并且當前讀返回的記錄,都會加鎖,保證其他事務不會再并發(fā)修改這條記錄。?
????????insert/update/delete
????????select ...for update
????????select ... lock in share mode
2. MVCC的底層實現(xiàn)
MVCC的目的就是多版本并發(fā)控制,在數(shù)據(jù)庫中的實現(xiàn),就是為了解決讀寫沖突,它的實現(xiàn)原理主要是依賴記錄中的 3個隱式字段,undo log ,Read View 來實現(xiàn)的。
InnoDB MVCC的實現(xiàn)基于undo log,通過回滾指針來構(gòu)建需要的版本記錄。通過ReadView來判斷哪些版本的數(shù)據(jù)可見。同時Purge線程是通過ReadView來清理舊版本數(shù)據(jù)。
2.1 三個隱式字段
DB_TRX_ID
????????6byte,最近修改(修改/插入)事務ID:記錄創(chuàng)建這條記錄/最后一次修改該記錄的事務ID
DB_ROLL_PTR
????????7byte,回滾指針,用于配合undo log,指向這條記錄的上一個版本
DB_ROW_ID
????????6byte,隱含的自增ID(隱藏主鍵),如果數(shù)據(jù)表沒有主鍵,InnoDB會自動以DB_ROW_ID產(chǎn)生一個聚簇索引
注意:
????????實際上每條記錄的頭信息(record header)里都有一個專門的bit(deleted flag)來表示當前記錄是否已經(jīng)被刪除

2.2 undo log
2.2.1?基本概念
undo log主要記錄的是數(shù)據(jù)的邏輯變化,為了在發(fā)生錯誤時回滾之前的操作,需要將之前的操作都記錄下來,然后在發(fā)生錯誤時才可以回滾。
作用:
????????用于事務的回滾
????????????????undo日志用于存放數(shù)據(jù)修改被修改前的值,如果這個修改出現(xiàn)異常,可以使用undo日志來實現(xiàn)回滾操作,保證事務的一致性。
????????????????undo日志,只將數(shù)據(jù)庫邏輯地恢復到原來的樣子,在回滾的時候,它實際上是做的相反的工作
????????用于MVCC
undo log的類型主要分為:
????????insert undo log
????????update undo log
2.2.2 insert undo log
insert undo log是指在insert 操作中產(chǎn)生的undo log,因為insert操作的記錄,只對事務本身可見,對其他事務不可見。故該undo log可以在事務提交后直接刪除,不需要進行purge操作。
2.2.3 update undo log
update undo log記錄的是對delete 和update操作產(chǎn)生的undo log,該undo log可能需要提供MVCC機制,因此不能再事務提交時就進行刪除。提交時放入undo log鏈表,等待purge線程進行最后的刪除。
具體工作原理需要分以下情況討論
2.2.3.1 更新主鍵
聚簇索引和二級索引都無法進行in place update,都會產(chǎn)生兩個版本
update分兩步執(zhí)行,先刪除該行,再插入一行目標行

2.2.3.2 更新非主鍵
聚簇索引可以in place update,二級索引產(chǎn)生兩個版本
聚簇索引記錄undo log,二級索引不記錄undo log
更新二級索引,同時需要判斷是否修改索引頁面的MAX_TRX_ID

2.2.3.3 刪除操作
刪除操作實際上不會直接刪除,而只是標記為刪除,最終的刪除操作是purge線程完成的

2.2.4 purge線程兩個主要作用是:
清理undo log
清除page里面帶有Delete_Bit標識的數(shù)據(jù)行。在InnoDB中,事務中的Delete操作實際上并不是真正的刪除掉數(shù)據(jù)行,而是一種Delete Mark操作,在記錄上標識刪除,真正的刪除工作需要后臺purge線程去完成。
2.3 Read View(讀視圖)
2.3.1 什么是Read View
Read View就是事務進行快照讀操作的時候生產(chǎn)的讀視圖(Read View),在該事務執(zhí)行的快照讀的那一刻,會生成數(shù)據(jù)庫系統(tǒng)當前的一個快照,記錄并維護系統(tǒng)當前活躍事務的ID(當每個事務開啟時,都會被分配一個ID, 這個ID是遞增的,所以最新的事務,ID值越大)
2.3.2 作用
Read View主要是用來做可見性判斷的, 即當我們某個事務執(zhí)行快照讀的時候,對該記錄創(chuàng)建一個Read View讀視圖,把它用來判斷當前事務能夠看到哪個版本的數(shù)據(jù),既可能是當前最新的數(shù)據(jù),也有可能是該行記錄的undo log里面的某個版本的數(shù)據(jù)。
2.3.3 核心算法(可見性算法)
Read View的三個屬性
trx_ids
????????一個數(shù)值列表,用來維護Read View生成時刻系統(tǒng)正活躍的事務ID
up_limit_id
????????記錄trx_ids列表中事務ID最小的ID
low_limit_id
????????ReadView生成時刻系統(tǒng)尚未分配的下一個事務ID,也就是目前已出現(xiàn)過的事務ID的最大值+1
可見性判斷的流程
遍歷DB_TRX_ID執(zhí)行以下步驟,直到找到當前事務可見的最新數(shù)據(jù):
????????遍歷方法:如果當前DB_TRX_ID這條記錄不滿足當前事務的可見性,可通過這條記錄的DB_ROLL_PTR回滾指針去取出undo log中前一個版本的DB_TRX_ID
step1:比較DB_TRX_ID?小于?up_limit_id
????????如果小于,則當前事務能看到DB_TRX_ID 所在的記錄;即該記錄是可見的最新的記錄
????????如果大于等于進入step2
step2:判斷 DB_TRX_ID?大于等于?low_limit_id
????????如果大于等于則代表DB_TRX_ID 所在的記錄在Read View生成后才出現(xiàn)的,那對當前事務肯定不可見,繼續(xù)遍歷下一個DB_TRX_ID
????????如果小于則進入step3
step3:判斷DB_TRX_ID 是否在活躍事務之中
????????如果在,則代表當前事務的Read View生成時刻,DB_TRX_ID這個事務還在活躍,還沒有Commit,DB_TRX_ID這個事務修改的數(shù)據(jù),當前事務也是看不見的;即對當前事務不可見,繼續(xù)遍歷下一個DB_TRX_ID
????????如果不在,則說明,DB_TRX_ID這個事務在當前事務的Read View生成之前就已經(jīng)Commit了,DB_TRX_ID這個事務修改的結(jié)果,對于當前事務是可見的
3. MVCC的工作原理
3.1 MVCC查詢的工作流程
3.1.1 查詢主鍵索引
生成Read View讀視圖
通過主鍵查找記錄,根據(jù)記錄里的DB_TRX_ID與Read View讀視圖進行可見性判斷
配合DB_ROLL_PTR回滾指針和undo log來找到當前事務可見的數(shù)據(jù)記錄
3.1.2 查詢二級索引
生成Read View讀視圖
比較讀視圖的up_limit_id與MAX_TRX_ID大小
如果MAX_TRX_ID??小于?本次Read View的up_limit_id,則全部可見,過濾記錄中的有效記錄
否則,無法通過二級索引判斷可見性,需要一次遍歷每條記錄,反查到聚簇索引記錄,通過聚簇索引記錄來判斷可見性
3.2 MVCC與隔離級別
MVCC?只在?Read?Commited?和 Repeatable?Read?兩種隔離級別下工作。
在RC隔離級別下,是每個快照讀都會生成并獲取最新的Read View;
這就是我們在RC級別下的事務中可以看到別的事務提交的更新的原因
在RR隔離級別下,則是同一個事務中的第一個快照讀才會創(chuàng)建Read View, 之后的快照讀獲取的都是同一個Read View。
即RR級別下,快照讀生成Read View時,Read View會記錄此時所有其他活動事務的快照,這些事務的修改對于當前事務都是不可見的。而早于Read View創(chuàng)建的事務所做的修改均是可見
4. 參考
https://www.cnblogs.com/AlmostWasteTime/p/11466520.html
http://www.itdecent.cn/p/8845ddca3b23
https://www.zhihu.com/question/27674363/answer/38034982
https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html
https://www.cnblogs.com/xibuhaohao/p/11947041.html
https://blog.csdn.net/qiuyepiaoling/article/details/8054346
https://blog.csdn.net/shaochenshuo/article/details/76137652
https://www.cnblogs.com/stevenczp/p/8018986.html
https://www.cnblogs.com/rongdi/p/13378892.html
http://www.itdecent.cn/p/336e4995b9b8
http://mysql.taobao.org/monthly/2015/04/01/
https://www.pianshen.com/article/50271826706/#Innodb__2
http://mysql.taobao.org/monthly/2018/11/04/
http://www.itdecent.cn/p/8845ddca3b23
https://www.cnblogs.com/micrari/p/8144339.html