數據庫並發控制是後端工程師進階必修課。本文從並發異常現象切入,層層遞進講解三級封鎖協議、四大隔離級別、MVCC 實現、鎖類型與兼容矩陣、兩段鎖協議、死鎖檢測與最佳實踐,幫助你建立完整的並發控制知識體系。
| 異常類型 | 現象描述 | 本質 |
|---|---|---|
| 髒讀 | A 讀取 B 未提交的修改,B 回滾導致 A 數據非法 | 讀取未提交數據 |
| 不可重複讀 | A 兩次讀取同一行,中間 B 修改並提交,結果不一致 | 讀取已提交的修改/刪除 |
| 幻讀 | A 兩次範圍查詢,中間 B 插入新行滿足條件,結果集變化 | 讀取已提交的新增 |
| 第一類丟失更新 | A 回滾覆蓋 B 已提交的修改 | 回滾覆蓋提交數據 |
| 第二類丟失更新 | A 提交覆蓋 B 已提交的修改 | 提交覆蓋提交數據 |
Oracle 默認 Read Committed 通過多版本機制天然避免髒讀;MySQL InnoDB 依賴 MVCC + 鎖解決上述問題。
注意:三級封鎖協議仍無法解決幻讀(需表級鎖或謂詞鎖)。
| 隔離級別 | 髒讀 | 不可重複讀 | 幻讀 | 並發性能 | MySQL 默認 |
|---|---|---|---|---|---|
| READ UNCOMMITTED | ✅ 可能 | ✅ 可能 | ✅ 可能 | 最高 | 否 |
| READ COMMITTED | ❌ 不會 | ✅ 可能 | ✅ 可能 | 高 | Oracle/SQL Server 默認 |
| REPEATABLE READ | ❌ 不會 | ❌ 不會 | ✅ 可能 | 中 | MySQL InnoDB 默認 |
| SERIALIZABLE | ❌ 不會 | ❌ 不會 | ❌ 不會 | 最低 | 否 |
SELECT ... LOCK IN SHARE MODE / FOR UPDATE、UPDATE/DELETE)加記錄鎖/間隙鎖/Next-Key Lock,防止幻讀DB_TRX_ID(最後修改事務 ID)、DB_ROLL_PTR(回滾指針)m_ids(活躍事務 ID 列表)、min_trx_id、max_trx_id、creator_trx_idtrx_id < min_trx_id 或 trx_id == creator_trx_id 的版本RR 級別:事務開始時創建 Read View,全程復用。
RC 級別:每次 SELECT 重新創建 Read View。
| 鎖類型 | 粒度 | 兼容性 | 典型場景 |
|---|---|---|---|
| 記錄鎖 | 單行 | X-X 互斥,S-S 兼容,S-X 互斥 | 主鍵/唯一索引等值查詢 + FOR UPDATE |
| 間隙鎖 | 區間 | G-G 兼容,G-X 互斥 | 範圍查詢防幻讀 |
| Next-Key Lock | 記錄+間隙 | 同記錄鎖 | RR 級別當前讀默認加鎖 |
| 插入意向鎖 | 間隙 | 與 G 鎖衝突 | INSERT 時自動獲取 |
| 表鎖 | 整表 | 意向鎖 (IS/IX) 配合 | DDL、無索引更新、SERIALIZABLE |
意向鎖:IS/IX 表示事務「意圖」在表中加 S/X 鎖,僅用於表級鎖與行級鎖兼容性快速判斷。
innodb_deadlock_detect = ON(默認)ERROR 1213 (HY000): Deadlock found 重試SELECT * FROM sys.innodb_lock_waits / information_schema.innodb_trxSET TRANSACTION READ ONLY 或連接參數 readOnly=true,InnoDB 可優化分配 Read View