MVCC實現機制


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 = '';  --(1select * from user where sex = '';  --(2commit;

  假設在執行這個事務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;

  執行結果如下:

  

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM