MVCC(Multi-Version Concurrency Control)是 InnoDB 實現高並發的核心技術,通過「讀不阻塞寫、寫不阻塞讀」大幅提升吞吐量。本文從底層存儲結構、版本鏈、ReadView 機制三個維度,配合具體事務演示,徹底講透 MVCC。
trx_id(創建版本)、roll_pointer(指向 Undo Log 版本鏈)、row_id(無主鍵時的隱藏主鍵)。m_ids(活躍事務 ID 列表)、min_trx_id、max_trx_id、creator_trx_id。+----------------+---------+----------+---------------+
| 當前記錄 | trx_id | roll_ptr | 數據列... |
+----------------+---------+----------+---------------+
│
▼ Undo Log 鏈
+----------------+---------+----------+---------------+
| 歷史版本 1 | trx_id | roll_ptr | 舊數據... |
+----------------+---------+----------+---------------+
│
▼
+----------------+---------+----------+---------------+
| 歷史版本 2 | trx_id | NULL | 更舊數據... |
+----------------+---------+----------+---------------+
事務讀取某版本記錄時,按順序判斷:
trx_id == creator_trx_id → 可見(自己修改的)。trx_id < min_trx_id → 可見(事務啟動前已提交)。trx_id > max_trx_id → 不可見(事務啟動後才開啟的事務)。min_trx_id ≤ trx_id ≤ max_trx_id:
trx_id IN m_ids → 不可見(活躍事務未提交)。trx_id NOT IN m_ids → 可見(已提交事務)。初始表 t(id PK, name, trx_id, roll_ptr),已有記錄 (1, 'a', 1, NULL)。
四事務並發(ID 分配順序):
SELECT * FROM t WHERE id=1(長事務,不提交)INSERT INTO t VALUES (2, 'b')DELETE FROM t WHERE id=1UPDATE t SET name='b' WHERE id=1T1 首次查詢:ReadView m_ids=[2,3,4,5], min=2, max=5
SELECT 返回 (1,'a')。T1 等待 10 分鐘後再次查詢(T2/T3/T4 均未提交):ReadView 不變,結果仍為 (1,'a') → 可重複讀成立。
若 T3 提交:DELETE 版本 trx=4 變為已提交,但 T1 ReadView 中 min=2, max=5, m_ids 仍含 4 → 仍不可見。
若 T4 提交:UPDATE 版本 trx=5 已提交,同理不可見。
只有 T1 提交後,新開啟的事務才能看到最新提交版本。
| 隔離級別 | ReadView 創建時機 | 效果 |
|---|---|---|
| Read Committed | 每條 SELECT 執行前 | 不可重複讀、幻讀 |
| Repeatable Read (默認) | 事務首次 SELECT 前 | 可重複讀,InnoDB 通過 Next-Key Lock 解決幻讀 |
SELECT ... LOCK IN SHARE MODE、SELECT ... FOR UPDATE 直接加鎖,不走 MVCC。MVCC 通過 Undo Log 版本鏈 + ReadView 可見性判斷,實現了無鎖一致性讀,是 InnoDB 高並發的基石。理解其原理,有助於排查長事務導致的 Undo Log 膨脹、History List Length 飆升、死鎖等疑難雜癥。