什么是MVCC
MVCC(Multi-Version Concurrency Control)多版本并發(fā)控制,是Mysql利用記錄的版本鏈和ReadView,來控制 Innodb 并發(fā)事務(wù)訪問相同記錄的行為。
版本鏈
在InnoDB引擎中,每一張表中都會包含兩個隱藏字段:trx_id、roll_pointer。
- trx_id:存儲事務(wù)字段,當(dāng)一個事務(wù)去操作某一行數(shù)據(jù)的時候,會將自己的事務(wù)ID賦值給trx_id字段;
-
roll_pointer:回滾指針,當(dāng)一個事務(wù)更新一行數(shù)據(jù)的時候,并不會馬上刪除掉舊的數(shù)據(jù)記錄,而是將更新之后數(shù)據(jù)的roll_pointer指向舊的數(shù)據(jù)記錄,然后把舊的數(shù)據(jù)記錄存儲到undo log中,形成一個版本。隨著更新的次數(shù)的增多所有的版本鏈成一條鏈,形成版本鏈。
版本鏈如下圖所示:
版本鏈
ReadView
ReadView中存在4個比較重要的概念
- m_ids:當(dāng)ReadView創(chuàng)建時,記錄當(dāng)前系統(tǒng)中所有活躍事務(wù)ID列表,即未提交事務(wù)ID列表;
- min_trx_id:當(dāng)ReadView創(chuàng)建時,記錄當(dāng)前系統(tǒng)中活躍事務(wù)最小事務(wù)ID,即最早創(chuàng)建且未提交的事務(wù)ID;
- max_trx_id:當(dāng)ReadView創(chuàng)建時,記錄當(dāng)前系統(tǒng)中應(yīng)該分配給下一個事務(wù)的ID,即預(yù)分配事務(wù)ID;
- creator_trx_id:當(dāng)ReadView創(chuàng)建時,記錄當(dāng)前事務(wù)ID,即創(chuàng)建ReadView的事務(wù)ID;
ReadView生成時機
- 讀已提交隔離級別:讀取數(shù)據(jù)前都會生成一個ReadView(當(dāng)前讀),解決臟讀;
- 可重復(fù)讀隔離級別:第一次讀取數(shù)據(jù)前生成一個readview(快照讀),解決不可重復(fù)讀和幻讀;
ReadView訪問過程
undo log的數(shù)據(jù)中包含的trx_id是否符合如下條件:
- trx_id == creator_trx_id,如果被訪問版本的trx_id與ReadView中的creator_trx_id值相等,說明當(dāng)前事務(wù)訪問的是自己修改過的記錄,所以該版本的記錄可以被當(dāng)前事務(wù)訪問;
- trx_id < min_trx_id,如果被訪問版本的trx_id的值小于ReadView中min_trx_id的值,說明生成該版本事務(wù)在當(dāng)前事務(wù)生成ReadView之前已經(jīng)提交,所以該版本的記錄可以被當(dāng)前事務(wù)訪問;
- trx_id ≥ max_trx_id,如果被訪問版本的trx_id的值大于等于ReadView中max_trx_id的值,說明生成該版本事務(wù)在當(dāng)前事務(wù)生成ReadView之后才被開啟,所以該版本的記錄不可以被當(dāng)前事務(wù)訪問;
-
min_tr_id ≤ trx_id < max_trx_id,如果被訪問版本trx_id的值在ReadView的min_trx_id和max_trx_id之間,則需要判斷被訪問版本是否在ReadView的 m_ids中存在;
如果在m_ids中存在,則說明創(chuàng)建readview時生成該版本的事務(wù)還是活躍的,該版本不可以被訪問;
如果在m_ids中不存在,則說明創(chuàng)建readview時生成該版本的事務(wù)已經(jīng)被提交,該版本可以被訪問
ReadView示例:

ReadView
