| 引擎 | 鎖粒度 | 死鎖可能 | 適用場景 |
|---|---|---|---|
| MyISAM/MEMORY | 表級 | 無 | 讀多寫少 |
| BDB | 頁面/表級 | 有 | 罕用 |
| InnoDB | 行級 | 有 | 高並發寫入 |
UPDATE/DELETE 掃描 WHERE 條件時,會鎖定**掃描到的所有索引記錄** + **鄰近鍵值** (Next-Key Lock)表結構:
CREATE TABLE tab_test (
id BIGINT PRIMARY KEY,
state INT,
time DATETIME,
INDEX idx_1 (state, time)
);
並發執行兩條 SQL:
-- 任務 1(掃描次級索引 idx_1)
UPDATE tab_test SET state=1064, time=NOW()
WHERE state=1061 AND time < DATE_SUB(NOW(), INTERVAL 30 MINUTE);
-- 任務 2(主鍵精確查找)
UPDATE tab_test SET state=1067, time=NOW()
WHERE id IN (9921180);
idx_1 → **先鎖次級索引記錄** → 需回表 → **等待主鍵索引鎖**state → **需鎖次級索引記錄** → 等待任務 1 持有的次級索引鎖-- 步驟 1:先查主鍵(走次級索引但只取 id)
SELECT id FROM tab_test
WHERE state=1061 AND time < DATE_SUB(NOW(), INTERVAL 30 MINUTE);
-- 步驟 2:按主鍵批次更新(走主鍵索引,鎖定順序一致)
UPDATE tab_test SET state=1064, time=NOW()
WHERE id IN (1001, 1002, 1003...);
核心原則:所有並發更新**統一按主鍵順序**獲取鎖,打破循環等待條件。
READ COMMITTED 減少間隙鎖innodb_print_all_deadlocks=ON 記錄完整死鎖日誌分析