一.什么是MVCC
二.一個小Demo
下面我們來看一個小demo,我這里新建來一張表mvcc_test,表字段有id和num。這里插入一筆數據 id=1 num=12
現在我們假設有3個事務,按以下順序執行(如下圖):
- 開啟事務A
- 開啟事務B
- 執行事務A查詢
- 執行事務B查詢
- 執行事務C
- 執行事務B更新
- 執行事務B查詢
- 執行事務A查詢
那么請問步驟7和8執行的結果的num分別是多少?
答案是:14和12
我們偉大的小平同志曾經說過:“實踐是檢驗真理的唯一標准”,這里我們實際來操作一下試試!!!


下面我們按照操作步驟執行
步驟1 ——開啟事務A
步驟2——開啟事務B
步驟3——執行查詢A
步驟4——執行查詢B
步驟5——執行事務C
步驟6——執行事務B更新
步驟7——執行事務B查詢
步驟8——執行事務A查詢並commit
很神奇對吧,下面我們就談談它的原理。
三.圖說原理
首先了解MVCC里面2個重要概念
快照讀和當前讀
快照讀:像不加鎖的select操作就是快照讀,即不加鎖的非阻塞讀;快照讀的前提是隔離級別不是串行級別,串行級別下的快照讀會退化成當前讀;
當前讀:就是它讀取的是記錄的最新版本,讀取時還要保證其他並發事務不能修改當前記錄,會對讀取的記錄進行加鎖。
InnerDB的事務管理
事務ID和順序遞增
在mysql的每一行數據中有3個隱藏字段
- DB_TRX_ID
6byte,最近修改(修改/插入)事務ID:記錄創建這條記錄/最后一次修改該記錄的事務ID - DB_ROLL_PTR
7byte,回滾指針,指向這條記錄的上一個版本(存儲於rollback segment里) - DB_ROW_ID
6byte,隱含的自增ID(隱藏主鍵),如果數據表沒有主鍵,InnoDB會自動以DB_ROW_ID產生一個聚簇索引
假設我們現在表中數據id=1的事務id=100
在執行步驟1和2之后,由於事務的順序遞增特性,事務A的事務id=101,事務B的id=102
在執行步驟3的時候因為是查詢,所以會生成一個num=12的快照,進行快照讀,步驟4同理
在執行步驟5時候,因為是更新操作,進行當前讀,事務C會創建一個新事務,事務id=103,並修改當前最新版本DB_TRX_ID=103,num變成13
此時執行步驟6,進行當前讀,事務B讀取讀DB_TRX_ID不是100,而是103,讀取到num為13進行更新操作,num變成14
執行步驟7查詢,進行快照讀還是事務A開啟時候讀快照所以num結果還是12。
執行步驟8查詢,因為在事務B中我們進行最后的更新操作,所以可以返回最新的num值14。