測試環(huán)境:Mysql 5.7.20-log
數(shù)據(jù)庫默認(rèn)隔離級別: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ù)的版本號卖局,用來和查詢每行記錄的版本號進(jìn)行比較。
每個事務(wù)又有自己的版本號双霍,這樣事務(wù)內(nèi)執(zhí)行CRUD操作時砚偶,就通過版本號的比較來達(dá)到數(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ù)查詢出來:
1) 刪除版本號未指定或者大于當(dāng)前事務(wù)版本號澄惊,即查詢事務(wù)開啟后確保讀取的行未被刪除。(即上述事務(wù)id為2的事務(wù)查詢時,依然能讀取到事務(wù)id為3所刪除的數(shù)據(jù)行)
2) 創(chuàng)建版本號小于或者等于當(dāng)前事務(wù)版本號 掸驱,就是說記錄創(chuàng)建是在當(dāng)前事務(wù)中(等于的情況)或者在當(dāng)前事務(wù)啟動之前的其他事物進(jìn)行的insert肛搬。(即事務(wù)id為2的事務(wù)只能讀取到create version<=2的已提交的事務(wù)的數(shù)據(jù)集)
補充:
1.MVCC手段只適用于Msyql隔離級別中的讀已提交和可重復(fù)讀.
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é)
客觀上,我們認(rèn)為他就是樂觀鎖的一整實現(xiàn)方式章郁,就是每行都有版本號枉氮,保存時根據(jù)版本號決定是否成功。
但由于Mysql的寫操作會加排他鎖(前文有講)暖庄,如果鎖定了還算不算是MVCC聊替?
了解樂觀鎖的小伙伴們,都知道其主要依靠版本控制培廓,即消除鎖定惹悄,二者相互矛盾,so從某種意義上來說医舆,Mysql的MVCC并非真正的MVCC俘侠,他只是借用MVCC的名號實現(xiàn)了讀的非阻塞而已象缀。