高併發秒殺/搶購:庫存量少(如 1),大量用戶同時下單,必須保證不超賣。
SELECT ... FOR UPDATE 在事務中對讀取行加排他鎖(X 鎖),阻塞其他事務的 FOR UPDATE 或 LOCK IN SHARE MODE 讀取,以及該行的 UPDATE/DELETE。讀取未加鎖的 SELECT 不受影響(MVCC 快照讀)。
BEGIN;
SELECT stock FROM goods WHERE id = 1 FOR UPDATE; -- 加鎖讀取
-- 應用層判斷 stock > 0
UPDATE goods SET stock = stock - 1 WHERE id = 1;
COMMIT;
用戶 A 執行上述事務,用戶 B 同樣執行 SELECT ... FOR UPDATE 會阻塞等待,直到 A 提交或回滾。鎖釋放後 B 讀到最新 stock(已扣減),判斷為 0 放棄下單,達到防超賣。
FOR UPDATE 鎖即釋放,失去保護。WHERE 條件必須走索引(最好是主鍵),否則會鎖全表(間隙鎖/表鎖),嚴重降低併發。innodb_lock_wait_timeout 避免無限等待。UPDATE goods SET stock = stock - 1, version = version + 1
WHERE id = 1 AND stock > 0 AND version = @old_version;
應用層重試機制配合樂觀鎖,適用於衝突率較低場景,無鎖等待開銷。