準(zhǔn)備
測試環(huán)境:Mysql 5.7.20-log
數(shù)據(jù)庫默認隔離級別:RR(Repeatable Read掌实,可重復(fù)讀)爪瓜,MVCC主要適用于Mysql的RC,RR隔離級別
創(chuàng)建一張存儲引擎為testmvcc的表路星,sql為:
CREATE TABLE testmvcc (
id int(11) DEFAULT NULL,
name varchar(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
什么是MVCC?
英文全稱為Multi-Version Concurrency Control,翻譯為中文即 多版本并發(fā)控制。在小編看來赞哗,他無非就是樂觀鎖的一種實現(xiàn)方式牌里。在Java編程中融柬,如果把樂觀鎖看成一個接口死嗦,MVCC便是這個接口的一個實現(xiàn)類而已。
特點
1.MVCC其實廣泛應(yīng)用于數(shù)據(jù)庫技術(shù)粒氧,像Oracle,PostgreSQL等也引入了該技術(shù)越除,即適用范圍廣
2.MVCC并沒有簡單的使用數(shù)據(jù)庫的行鎖,而是使用了行級鎖外盯,row_level_lock,而非InnoDB中的innodb_row_lock.
基本原理
MVCC的實現(xiàn)摘盆,通過保存數(shù)據(jù)在某個時間點的快照來實現(xiàn)的。這意味著一個事務(wù)無論運行多長時間饱苟,在同一個事務(wù)里能夠看到數(shù)據(jù)一致的視圖孩擂。根據(jù)事務(wù)開始的時間不同,同時也意味著在同一個時刻不同事務(wù)看到的相同表里的數(shù)據(jù)可能是不同的箱熬。
基本特征
- 每行數(shù)據(jù)都存在一個版本类垦,每次數(shù)據(jù)更新時都更新該版本。
- 修改時Copy出當(dāng)前版本隨意修改坦弟,各個事務(wù)之間無干擾护锤。
- 保存時比較版本號,如果成功(commit)酿傍,則覆蓋原記錄烙懦;失敗則放棄copy(rollback)
InnoDB存儲引擎MVCC的實現(xiàn)策略
在每一行數(shù)據(jù)中額外保存兩個隱藏的列:當(dāng)前行創(chuàng)建時的版本號和刪除時的版本號(可能為空,其實還有一列稱為回滾指針赤炒,用于事務(wù)回滾氯析,不在本文范疇)。這里的版本號并不是實際的時間值莺褒,而是系統(tǒng)版本號掩缓。每開始新的事務(wù),系統(tǒng)版本號都會自動遞增遵岩。事務(wù)開始時刻的系統(tǒng)版本號會作為事務(wù)的版本號你辣,用來和查詢每行記錄的版本號進行比較。
每個事務(wù)又有自己的版本號尘执,這樣事務(wù)內(nèi)執(zhí)行CRUD操作時舍哄,就通過版本號的比較來達到數(shù)據(jù)版本控制的目的。
MVCC下InnoDB的增刪查改是怎么work的
1.插入數(shù)據(jù)(insert):記錄的版本號即當(dāng)前事務(wù)的版本號
執(zhí)行一條數(shù)據(jù)語句:insert into testmvcc values(1,"test");
假設(shè)事務(wù)id為1誊锭,那么插入后的數(shù)據(jù)行如下:
2表悬、在更新操作的時候,采用的是先標(biāo)記舊的那行記錄為已刪除丧靡,并且刪除版本號是事務(wù)版本號蟆沫,然后插入一行新的記錄的方式籽暇。
比如,針對上面那行記錄饭庞,事務(wù)Id為2 要把name字段更新
update table set name= 'new_value' where id=1;
3戒悠、刪除操作的時候,就把事務(wù)版本號作為刪除版本號但绕。比如
delete from table where id=1;
4救崔、查詢操作:
從上面的描述可以看到惶看,在查詢時要符合以下兩個條件的記錄才能被事務(wù)查詢出來:
刪除版本號未指定或者大于當(dāng)前事務(wù)版本號捏顺,即查詢事務(wù)開啟后確保讀取的行未被刪除。(即上述事務(wù)id為2的事務(wù)查詢時纬黎,依然能讀取到事務(wù)id為3所刪除的數(shù)據(jù)行)
創(chuàng)建版本號 小于或者等于 當(dāng)前事務(wù)版本號 幅骄,就是說記錄創(chuàng)建是在當(dāng)前事務(wù)中(等于的情況)或者在當(dāng)前事務(wù)啟動之前的其他事物進行的insert。
(即事務(wù)id為2的事務(wù)只能讀取到create version<=2的已提交的事務(wù)的數(shù)據(jù)集)
補充:
1.MVCC手段只適用于Msyql隔離級別中的讀已提交(Read committed)和可重復(fù)讀(Repeatable Read).
2.Read uncimmitted由于存在臟讀本今,即能讀到未提交事務(wù)的數(shù)據(jù)行拆座,所以不適用MVCC.
原因是MVCC的創(chuàng)建版本和刪除版本只要在事務(wù)提交后才會產(chǎn)生。
3.串行化由于是會對所涉及到的表加鎖冠息,并非行鎖挪凑,自然也就不存在行的版本控制問題。
4.通過以上總結(jié)逛艰,可知躏碳,MVCC主要作用于事務(wù)性的,有行鎖控制的數(shù)據(jù)庫模型散怖。
關(guān)于Mysql中MVCC的總結(jié)
客觀上菇绵,我們認為他就是樂觀鎖的一整實現(xiàn)方式,就是每行都有版本號镇眷,保存時根據(jù)版本號決定是否成功咬最。
但由于Mysql的寫操作會加排他鎖(前文有講),如果鎖定了還算不算是MVCC欠动?
了解樂觀鎖的小伙伴們永乌,都知道其主要依靠版本控制,即消除鎖定具伍,二者相互矛盾翅雏,so從某種意義上來說,Mysql的MVCC并非真正的MVCC沿猜,他只是借用MVCC的名號實現(xiàn)了讀的非阻塞而已枚荣。