SELECT ... LOCK IN SHARE MODE (S)、SELECT ... FOR UPDATE (X)。表級鎖,標識事務「意圖」在表中某行加 S/X 鎖。解決「表鎖與行鎖衝突檢查」全表掃描問題:事務加行 X 鎖前先加表 IX,另一事務想加表 S 鎖只需檢查表級 IX 即知衝突,無需遍歷所有行。
| 維度 | 悲觀鎖 | 樂觀鎖 |
|---|---|---|
| 實現 | FOR UPDATE / LOCK IN SHARE MODE | 版本號字段 + UPDATE ... WHERE version = old |
| 適用場景 | 寫多、衝突頻繁、事務短 | 讀多寫少、衝突稀疏、業務邏輯允許重試 |
| 阻塞 | 有(等待鎖) | 無(CAS 失敗應用層重試) |
-- 事務 1 -- 事務 2
UPDATE t SET v=1 WHERE id=1; UPDATE t SET v=2 WHERE id=2;
SLEEP 1; SLEEP 2;
UPDATE t SET v=2 WHERE id=2; UPDATE t SET v=1 WHERE id=1;
COMMIT; COMMIT;
若交替執行至 SLEEP,雙方各持一鎖等待對方 → 死鎖。
SELECT ... WHERE id BETWEEN 10 AND 20 FOR UPDATE 會鎖定 (10,20) 區間,防止幻讀(新插入 id=15)。RR 隔離級別下默認啟用。
create_version、delete_version。create_version ≤ 當前版本 AND (delete_version > 當前版本 OR delete_version IS NULL) 的行。效果:不加鎖實現一致性非阻塞讀,解決髒讀、不可重複讀、幻讀(RR 下)。
| SQL | 鎖類型 | 備註 |
|---|---|---|
| SELECT ... | 無鎖 | 一致性非阻塞讀 (MVCC) |
| SELECT ... LOCK IN SHARE MODE | S 鎖 | 需索引,否則表鎖 |
| SELECT ... FOR UPDATE | X 鎖 | 需索引,否則表鎖 |
| UPDATE ... | X 鎖 | 需索引,否則表鎖 |
| DELETE ... | X 鎖 | 需索引,否則表鎖 |
-- 事務 1
SET autocommit=0; BEGIN;
SELECT * FROM biz_pay_task WHERE id=1 FOR UPDATE; -- 持有 X 鎖
-- 事務 2
SET autocommit=0; BEGIN;
SELECT * FROM biz_pay_task WHERE id=1 LOCK IN SHARE MODE; -- 阻塞,等事務 1 COMMIT
X 鎖與 S 鎖互斥,驗證排他性。