事務隔離級別決定了併發事務之間的可見性邊界,直接影響資料一致性與系統吞吐。MySQL InnoDB 預設 **REPEATABLE READ (RR)**,並透過 **MVCC(多版本併發控制)** 解決幻讀。本文系統闡述四大隔離級別的理論定義、InnoDB 實現機制、鎖行為差異,並提供實測腳本量化效能影響。
| 級別 | 髒讀 | 不可重複讀 | 幻讀 | 典型鎖策略 |
|---|---|---|---|---|
| READ UNCOMMITTED (RU) | ✅ 可能 | ✅ 可能 | ✅ 可能 | 無共享鎖,極低隔離 |
| READ COMMITTED (RC) | ❌ | ✅ 可能 | ✅ 可能 | 讀取加瞬間共享鎖,立即釋放 |
| REPEATABLE READ (RR) | ❌ | ❌ | ❌ (MVCC 解決) | 讀取加共享鎖持有至提交,Next-Key Lock 防幻讀 |
| SERIALIZABLE | ❌ | ❌ | ❌ | 全表範圍共享鎖,單線程串行 |
DB_TRX_ID(建立事務 ID)、DB_ROLL_PTR(回滾指標)。m_ids(活躍事務 ID 列表)、min_trx_id、max_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 ∈ m_ids 不可見,否則可見。| SQL 類型 | 加鎖模式 | 說明 |
|---|---|---|
SELECT ... LOCK IN SHARE MODE | S 鎖 (共享) | 阻塞寫,允許讀 |
SELECT ... FOR UPDATE | X 鎖 (排他) | 阻塞讀寫 |
UPDATE/DELETE/INSERT | X 鎖 | 記錄鎖 + 間隙鎖 = Next-Key Lock |
| 唯一索引等值查詢 | Record Lock | 僅鎖記錄,無間隙 |
| 非唯一索引/範圍查詢 | Next-Key Lock | 鎖區間,防幻讀 |
# Sysbench 準備 sysbench /usr/share/sysbench/oltp_read_write.lua \ --mysql-host=127.0.0.1 --mysql-port=3306 \ --mysql-user=sbtest --mysql-password=sbtest \ --mysql-db=sbtest --tables=10 --table-size=100000 \ prepare
for level in "READ-UNCOMMITTED" "READ-COMMITTED" "REPEATABLE-READ" "SERIALIZABLE"; do
mysql -uroot -p -e "SET GLOBAL transaction_isolation='$level';"
sysbench /usr/share/sysbench/oltp_read_write.lua \
--mysql-host=127.0.0.1 --mysql-user=sbtest --mysql-password=sbtest \
--mysql-db=sbtest --threads=64 --time=60 --report-interval=10 \
run > "sysbench_${level}.log"
done
| 隔離級別 | TPS (avg) | QPS (avg) | 95% Latency (ms) | 鎖等待佔比 |
|---|---|---|---|---|
| READ UNCOMMITTED | ~4200 | ~84000 | 1.8 | 0.1% |
| READ COMMITTED | ~3900 | ~78000 | 2.1 | 0.3% |
| REPEATABLE READ | ~3600 | ~72000 | 2.5 | 0.8% |
| SERIALIZABLE | ~800 | ~16000 | 18.5 | 12.4% |
結論:RR 為預設平衡點;RC 適合高併發讀多寫少、可容忍不可重複讀;SERIALIZABLE 僅用於極嚴格一致性場景(如庫存扣減單線程)。
Next-Key Lock 鎖住「記錄 + 記錄前間隙」,阻止其他事務在範圍內插入新行。MVCC 快照讀不加鎖,但當前讀(FOR UPDATE、LOCK IN SHARE MODE、DML)會加 Next-Key Lock。
-- 查看當前鎖等待 SELECT * FROM performance_schema.data_lock_waits\G -- 查看死鎖歷史 SHOW ENGINE INNODB STATUS\G -- 最近一次死鎖詳情
常見死鎖模式:
事務 A 鎖住索引 1 → 嘗試鎖索引 2
事務 B 鎖住索引 2 → 嘗試鎖索引 1
修正:統一業務邏輯加鎖順序(按主鍵遞增)。
purge 線程清理 Undo Log,導致 History List Length 暴增。監控:SELECT * FROM information_schema.innodb_trx WHERE trx_started < NOW() - INTERVAL 60 SECOND;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED。SELECT ... FOR UPDATE SKIP LOCKED (MySQL 8.0) 實現佇列消費無阻塞。Innodb_row_lock_waits、Innodb_row_lock_time_avg、Trx_rseg_history_len。結語: 隔離級別是一致性與效能的權衡桿。InnoDB 以 MVCC + Next-Key Lock 在 RR 級別同時實現高併發與無幻讀,堪稱經典工程設計。理解其底層機制,能讓我們在架構層面做出正確選型,在應用層面編寫無鎖爭用的高效 SQL。