什么是MVCC
MVCC(Multi-Version Concurrency Control)多版本并發(fā)控制褂删,是Mysql利用記錄的版本鏈和ReadView,來控制 Innodb 并發(fā)事務(wù)訪問相同記錄的行為。
版本鏈
在InnoDB引擎中,每一張表中都會(huì)包含兩個(gè)隱藏字段:trx_id、roll_pointer。
- trx_id:存儲(chǔ)事務(wù)字段萍丐,當(dāng)一個(gè)事務(wù)去操作某一行數(shù)據(jù)的時(shí)候,會(huì)將自己的事務(wù)ID賦值給trx_id字段放典;
-
roll_pointer:回滾指針逝变,當(dāng)一個(gè)事務(wù)更新一行數(shù)據(jù)的時(shí)候,并不會(huì)馬上刪除掉舊的數(shù)據(jù)記錄奋构,而是將更新之后數(shù)據(jù)的roll_pointer指向舊的數(shù)據(jù)記錄壳影,然后把舊的數(shù)據(jù)記錄存儲(chǔ)到undo log中,形成一個(gè)版本弥臼。隨著更新的次數(shù)的增多所有的版本鏈成一條鏈宴咧,形成版本鏈。
版本鏈如下圖所示:
ReadView
ReadView中存在4個(gè)比較重要的概念
- m_ids:當(dāng)ReadView創(chuàng)建時(shí)径缅,記錄當(dāng)前系統(tǒng)中所有活躍事務(wù)ID列表掺栅,即未提交事務(wù)ID列表;
- min_trx_id:當(dāng)ReadView創(chuàng)建時(shí)纳猪,記錄當(dāng)前系統(tǒng)中活躍事務(wù)最小事務(wù)ID氧卧,即最早創(chuàng)建且未提交的事務(wù)ID;
- max_trx_id:當(dāng)ReadView創(chuàng)建時(shí)氏堤,記錄當(dāng)前系統(tǒng)中應(yīng)該分配給下一個(gè)事務(wù)的ID假抄,即預(yù)分配事務(wù)ID;
- creator_trx_id:當(dāng)ReadView創(chuàng)建時(shí)丽猬,記錄當(dāng)前事務(wù)ID,即創(chuàng)建ReadView的事務(wù)ID熏瞄;
ReadView生成時(shí)機(jī)
- 讀已提交隔離級(jí)別:讀取數(shù)據(jù)前都會(huì)生成一個(gè)ReadView(當(dāng)前讀)脚祟,解決臟讀;
- 可重復(fù)讀隔離級(jí)別:第一次讀取數(shù)據(jù)前生成一個(gè)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時(shí)生成該版本的事務(wù)還是活躍的,該版本不可以被訪問丁存;
如果在m_ids中不存在肩杈,則說明創(chuàng)建readview時(shí)生成該版本的事務(wù)已經(jīng)被提交,該版本可以被訪問
ReadView示例: