一:什么是MVCC?
多版本并發控制,更好的方式去處理讀-寫沖突,就是為了查詢一些正在被另一個事務更新的行,并且可以看到它們被更新之前的值,這樣在做查詢的時候就不用等待另一個事務釋放鎖。
二: 快照讀與當前讀
快照圖:讀取的是快照數據,不加鎖的簡單的 SELECT 都屬于快照讀
SELECT * FROM player WHERE ...
當前讀:讀取的是記錄的最新版本,加鎖的 SELECT,或者對數據進行增刪改都會進行當前讀
SELECT * FROM XX_table LOCK IN SHARE MODE;
SELECT * FROM xx_table FOR UPDATE;
INSERT INTO xx_table ...
DELETE FROM xx_table ...
UPDATE xx_table ...
三:MVCC實現原理
MVCC 的實現依賴于:隱藏字段、Undo Log、Read View。
- 隱藏字段:trx_id,roll_pointer
- ReadView:Readview 就是事務在使用MVCC機制進行快照讀操作時產生的讀視圖。當事務啟動時,會生成數據庫系統當前的一個快照,InnoDB 為每個事務構造了一個數組,用來記錄并維護系統當前活躍事務的ID(“活躍”指的就是,啟動了但還沒提交)。
四:MVCC整體操作流程
- 首先獲取事務自己的版本號,也就是事務 ID;
- 獲取 ReadView;
- 查詢得到的數據,然后與 ReadView 中的事務版本號進行比較;
- 如果不符合 ReadView 規則,就需要從 Undo Log 中獲取歷史快照;
- 最后返回符合規則的數據。
ReadView的規則
(1)如果被訪問版本的trx_id屬性值與ReadView中的 creator_trx_id 值相同,意味著當前事務在訪問它自己修改過的記錄,所以該版本可以被當前事務訪問。
(2)如果被訪問版本的trx_id屬性值小于ReadView中的 up_limit_id 值,表明生成該版本的事務在當前事務生成ReadView前已經提交,所以該版本可以被當前事務訪問。
(3)如果被訪問版本的trx_id屬性值大于或等于ReadView中的 low_limit_id 值,表明生成該版本的事務在當前事務生成ReadView后才開啟,所以該版本不可以被當前事務訪問。
(4)如果被訪問版本的trx_id屬性值在ReadView的 up_limit_id 和 low_limit_id 之間,那就需要判斷一下trx_id屬性值是不是在 trx_ids 列表中。
如果在,說明創建ReadView時生成該版本的事務還是活躍的,該版本不可以被訪問。
如果不在,說明創建ReadView時生成該版本的事務已經被提交,該版本可以被訪問
五:舉例說明
讀已提交(READ COMMITTED)隔離級別下:一個事務中的每一次 SELECT 查詢都會重新獲取一次Read View。
可重復讀隔離級別下:因為一個事務只在第一次 SELECT 的時候會獲取一次 Read View,而后面所有的 SELECT 都會復用這個 Read View