1. MVCC簡介
1.1 什么是MVCC
MVCC(Multiversion concurrency control )是一種多版本並發控制機制。
1.2 MVCC是為了解決什么問題?
並發訪問(讀或寫)數據庫時,對正在事務內處理的數據做多版本的管理。以達到用來避免寫操作的堵塞,從而引發讀操作的並發問題。
大家都應該知道,鎖機制可以控制並發操作,但是其系統開銷較大,而MVCC可以在大多數情況下代替行級鎖,使用MVCC,能降低其系統開銷。
1.3 MVCC實現
MVCC是通過保存數據在某個時間點的快照來實現的。不同存儲引擎的MVCC實現是不同的,典型的有樂觀並發控制和悲觀並發控制。當我們創建表完成后,mysql會自動為每個表添加 數據版本號(最后更新數據的事務id)db_trx_id 刪除版本號 db_roll_pt (數據刪除的事務id) 事務id由mysql數據庫自動生成,且遞增。
2.MVCC 具體實現分析
2.1 MVCC邏輯流程-插入(insert)
如下圖,同一事務中(假設事務id=1)插入兩條記錄,記錄的數據版本號為事務id=1,刪除版本號為null
start transaction;(事務id為1) INSERT INTO user (name,sex) VALUES ('張三','男'); INSERT INTO user (name,sex) VALUES ('李四','男'); commit;
對應在數據中的表如下(后面兩列是隱藏列,我們通過查詢語句並看不到)
2.2 MVCC邏輯流程-查詢(select)
查詢時需要同時滿足以下兩個條件
1、查找數據版本號,早於(小於等於)當前事務id的數據行。 這樣可以確保事務讀取的數據是事務之前已經存在的。或者是當前事務插入或修改的。
2、查找刪除版本號為null 或者大於當前事務版本號的記錄。 這樣確保取出來的數據在當前事務開啟之前沒有被刪除。
如下圖,假如有一個事務中執行查詢(假設事務id=2)
start transaction;(事務id為2) select * from user where sex = '男'; --(1) select * from user where sex = '男'; --(2) commit;
假設在執行這個事務ID為2的過程中,剛執行到(1),這時有另一個事務(假設事務id=3)往這個表里插入了一條數據;
start transaction;(事務id為3) INSERT INTO user (name,sex) VALUES ('王五','男'); commit;
此時表中的數據如下:
然后接着執行事務 id=2 中的(2),由於id=3的數據的創建時間(事務ID為3),執行當前事務的ID為2,而InnoDB只會查找事務ID小於等於當前事務ID的數據行,所以 id=3 的數據行並不會在執行事務 id=2 中的 (2) 被檢索出來。在事務 id=2 中的兩條select 語句檢索出來的數據都只會下表:
2.3 MVCC邏輯流程-刪除(delete)
如下圖,假如有一個事務中執行查詢(假設事務id=4)
start transaction;(事務id為4) select * from user where sex = '男'; --(1) select * from user where sex = '男'; --(2) commit;
假設事務 id=4 剛執行到(1),此時有另外一個事務 id=5 執行了刪除語句,會更新數據的刪除版本號為當前事務id = 5
start transaction;(事務id為5) DELETE FROM user WHERE id = 1; commit;
此時數據庫表中數據如下:
接着執行事務 id=4的事務(2),根據SELECT 檢索條件可以知道,它會檢索創建時間(創建事務的ID)小於當前事務ID的行和刪除時間(刪除事務的ID)大於當前事務的行,表中id=1的行由於刪除時間(刪除事務的ID)大於當前事務的ID,所以事務 id=2 的(2)在執行的時候也會把表中 id=1 的數據檢索出來,所以事務4中的兩條select 語句檢索出來的數據都如下:
2.4 MVCC邏輯流程-修改(update)
可以理解為,當一個事務中 修改一條記錄時, 是先復制該數據,新數據數據版本號為當前事務id,刪除版本號為 null 。然后更新 原來數據的刪除版本號為 當前事務id。如下:
假如一個事務 id=6 執行了一條update語句
start transaction;(事務id為6) UPDATE user SET name='李四1' WHERE id = 2 commit;
執行結果如下: