準備
測試環境:Mysql 5.7.20-log
資料庫預設隔離級别:RR(Repeatable Read,可重複讀),MVCC主要适用于Mysql的RC,RR隔離級别
建立一張存儲引擎為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,翻譯為中文即 多版本并發控制。在小編看來,他無非就是樂觀鎖的一種實作方式。在Java程式設計中,如果把樂觀鎖看成一個接口,MVCC便是這個接口的一個實作類而已。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBHL0FWby9mZvwVZnFWbp1zczV2YvJHctM3cv1Ce-ITTql1aGpXTtJ1RNpmUE1UNBpXT3tGRPlXW61UMFpHTsR2VZRHbXxkakd0Y2VlMalnRHJmdwIjYqVzQjBjRHRmeC5GT1E0MMZ3bENGMShUYvwlbj5yZtlmbkN3YuQnclZnbvN2Ztl2Lc9CX6MHc0RHaiojIsJye.jpg)
特點
1.MVCC其實廣泛應用于資料庫技術,像Oracle,PostgreSQL等也引入了該技術,即适用範圍廣
2.MVCC并沒有簡單的使用資料庫的行鎖,而是使用了行級鎖,row_level_lock,而非InnoDB中的innodb_row_lock.
基本原理
MVCC的實作,通過儲存資料在某個時間點的快照來實作的。這意味着一個事務無論運作多長時間,在同一個事務裡能夠看到資料一緻的視圖。根據事務開始的時間不同,同時也意味着在同一個時刻不同僚務看到的相同表裡的資料可能是不同的。
基本特征
- 每行資料都存在一個版本,每次資料更新時都更新該版本。
- 修改時Copy出目前版本随意修改,各個事務之間無幹擾。
- 儲存時比較版本号,如果成功(commit),則覆寫原記錄;失敗則放棄copy(rollback)
InnoDB存儲引擎MVCC的實作政策
在每一行資料中額外儲存兩個隐藏的列:目前行建立時的版本号和删除時的版本号(可能為空,其實還有一列稱為復原指針,用于事務復原,不在本文範疇)。這裡的版本号并不是實際的時間值,而是系統版本号。每開始新的事務,系統版本号都會自動遞增。事務開始時刻的系統版本号會作為事務的版本号,用來和查詢每行記錄的版本号進行比較。
每個事務又有自己的版本号,這樣事務内執行CRUD操作時,就通過版本号的比較來達到資料版本控制的目的。
MVCC下InnoDB的增删查改是怎麼work的
1.插入資料(insert):記錄的版本号即目前事務的版本号
執行一條資料語句:insert into testmvcc values(1,"test");
假設事務id為1,那麼插入後的資料行如下:
2、在更新操作的時候,采用的是先标記舊的那行記錄為已删除,并且删除版本号是事務版本号,然後插入一行新的記錄的方式。
比如,針對上面那行記錄,事務Id為2 要把name字段更新
update table set name= 'new_value' where id=1;
3、删除操作的時候,就把事務版本号作為删除版本号。比如
delete from table where id=1;
4、查詢操作:
從上面的描述可以看到,在查詢時要符合以下兩個條件的記錄才能被事務查詢出來:
1) 删除版本号未指定或者大于目前事務版本号,即查詢事務開啟後確定讀取的行未被删除。(即上述事務id為2的事務查詢時,依然能讀取到事務id為3所删除的資料行)
2) 建立版本号 小于或者等于 目前事務版本号 ,就是說記錄建立是在目前事務中(等于的情況)或者在目前事務啟動之前的其他事物進行的insert。
(即事務id為2的事務隻能讀取到create version<=2的已送出的事務的資料集)
補充:
1.MVCC手段隻适用于Msyql隔離級别中的讀已送出(Read committed)和可重複讀(Repeatable Read).
2.Read uncimmitted由于存在髒讀,即能讀到未送出事務的資料行,是以不适用MVCC.
原因是MVCC的建立版本和删除版本隻要在事務送出後才會産生。
3.串行化由于是會對所涉及到的表加鎖,并非行鎖,自然也就不存在行的版本控制問題。
4.通過以上總結,可知,MVCC主要作用于事務性的,有行鎖控制的資料庫模型。
關于Mysql中MVCC的總結
客觀上,我們認為他就是樂觀鎖的一整實作方式,就是每行都有版本号,儲存時根據版本号決定是否成功。
但由于Mysql的寫操作會加排他鎖(前文有講),如果鎖定了還算不算是MVCC?
了解樂觀鎖的小夥伴們,都知道其主要依靠版本控制,即消除鎖定,二者互相沖突,so從某種意義上來說,Mysql的MVCC并非真正的MVCC,他隻是借用MVCC的名号實作了讀的非阻塞而已。