在 REPEATABLE READ 隔離級下,SELECT ... FOR UPDATE 與 LOCK IN SHARE MODE 皆會等待其他事務提交。關鍵差異:LOCK IN SHARE MODE 易於 UPDATE 時產生死鎖,若後續需更新同表,**務必使用 FOR UPDATE**。
-- 不安全:兩條語句間有間隙
SELECT quantity FROM products WHERE id=3;
UPDATE products SET quantity = 1 WHERE id=3;
間隙期若被其他事務扣減庫存至 0,本事務仍會錯誤執行 UPDATE。
SET AUTOCOMMIT=0;
BEGIN;
SELECT quantity FROM products WHERE id=3 FOR UPDATE; -- 鎖定該行
-- 業務邏輯判斷 quantity > 0
UPDATE products SET quantity = 1 WHERE id=3;
COMMIT;
SELECT ... FOR UPDATE 同一行會阻塞,直到 COMMITSELECT 不受影響(MVCC 快照讀)| SQL 範例 | 鎖類型 | 原因 |
|---|---|---|
WHERE id = '3' (PK 存在) | Row Lock | 明確指定主鍵 |
WHERE id = '-1' (PK 不存在) | 無鎖 | 無匹配行 |
WHERE name = 'Mouse' (非 PK) | Table Lock | 無索引/非主鍵 |
WHERE id <> '3' | Table Lock | 範圍條件非精確匹配 |
WHERE id LIKE '3' | Table Lock | 模糊匹配導致全表掃描 |
LOCK TABLES,易死鎖開兩個 MySQL Command 視窗交互觀察鎖等待狀態。