Mysql中MVCC的使用及原理詳解
準備
測試環境: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便是這個介面的一個實現類而已。
特點
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的名號實現了讀的非阻塞而已。