MVCC(多版本併發控制)詳解
在 MySQL InnoDB儲存引擎下,RC、RR 基於 MVCC 進行併發事務控制, MVCC 是基於“資料版本”對併發事務進行訪問
用一個例子來解釋一下,下面是一張事務執行流程圖:
稍微解釋一下:
-
事務 A
將id=1088
的記錄的name
改為 “張三”,並提交 -
事務 B
將id=1088
的記錄的name
改為 “張小三”,並提交 -
事務 C
將id=1088
的記錄的name
改為 “張老三”,並提交 -
事務 D
只是去查詢
id=1088 的記錄
首先模擬一下在 RC 隔離級別下:事務D 第一次讀取的資料是 “張三”,第二次讀取的就是“張小三”
這裡應該很好理解,因為在 RC 隔離級別下,事務D 能讀到 commit 的資料,所以就導致了“不可重複讀”問題
如果使用 RR 隔離級別,事務D 的兩次讀取都是 “張三”RR 隔離級別
MVCC
實現的,MVCC
又依賴 UNDO_LOG
,UNDO_LOG
就是回滾日誌,它是一個版本鏈,它記錄了上一次版本的資料變化eg:事務 B 把“張三”改為了“張小三”,在
UNDO_LOG
中的體現如下:注:最原始的資料,也就是最下面這一條,它的
事務ID
和 回滾指標
都是 null
瞭解了 UNDO_LOG 之後,現在引入一個新的名詞:
ReadView
(快照讀)快照都就是普通的 sql 查詢語句:select ....
有了快照讀就有當前讀,當前讀是指:
Insert、Update、Delete、
Select ... for update
Select ... lock in share mode
ReadView 資料結構
圖是從 IT老齊 那兒盜的,稍微解釋一下:
m_ids 未提交的事務,不允許讀
min_trx_id 就是快要執行完的事務 id
max_trx_id 就是下一個新的事務的 id
creator_trx_id 就是建立這個 ReadView 是哪個事務
RC 原理
RC(讀已提交):在每一次執行快照讀時生成 ReadView,根據上面的例子
讀了兩次,生成了兩個 ReadView,先看第一個 ReadView,因為在這個 ReadView 生成的時候,事務1 已經 commit 了,所以他不在活躍事務集合裡面,所以 m_ids 是 2,3,4
最小活躍事務就是 2 沒有異議
預分配事務id 就是 4+1 = 5
當前的 ReadView 是事務 4 建立的,所以 creator_trx_id = 4
第二個 ReadView 也是一樣的的邏輯
版本鏈資料訪問規則:
RR 原理
可重複讀原理很簡單,就是複用 ReadView
eg:在第二次查詢的時候,生成的 ReadView 是複用前一次的,所以不會造成 不可重複讀
RR 能解決幻讀嗎?
能,但不完全能。
如果是多次快照讀,ReadView會產生複用,沒有幻讀產生
但是當多次快照讀中間存在當前讀,ReadView會重新生成,導致產生幻讀