SELECT ... FOR UPDATE 是手動加行級排他鎖的核心語法,支援 WAIT/NOWAIT/SKIP LOCKED 三種等待模式,適用於「先鎖後改」的業務邏輯。
SELECT ... FOR UPDATE [OF column_list] [WAIT n | NOWAIT | SKIP LOCKED];
| 模式 | 語法 | 行為 | 適用場景 |
|---|---|---|---|
| 預設等待 | FOR UPDATE | 無限期等待鎖釋放 | 批次作業、低併發 |
| 等待 N 秒 | FOR UPDATE WAIT 5 | 超時回傳 ORA-30006 | 線上交易、需控制回應時間 |
| 不等待 | FOR UPDATE NOWAIT | 立即回傳 ORA-00054 | 高併發搶單、秒殺 |
| 跳過已鎖 | FOR UPDATE SKIP LOCKED | 略過被鎖行,只回傳可鎖行 | 佇列消費者、分散式任務分派 |
-- 消費者進程
LOOP
SELECT id, payload
INTO v_id, v_payload
FROM job_queue
WHERE status = 'PENDING'
FOR UPDATE SKIP LOCKED; -- 只拿未被處理的任務
-- 處理業務
process_job(v_payload);
UPDATE job_queue SET status = 'DONE' WHERE id = v_id;
COMMIT;
END LOOP;
多消費者並發時,SKIP LOCKED 保證每個任務只被一個消費者處理,無需應用層協調。
SELECT o.order_id, o.amount, c.credit_limit
FROM orders o, customers c
WHERE o.cust_id = c.cust_id
AND o.status = 'NEW'
FOR UPDATE OF o.amount; -- 只鎖 orders.amount,不鎖 customers 表
避免不必要的鎖擴大,減少衝突。
FOR UPDATE 鎖在 COMMIT/ROLLBACK 時釋放,**不可**在游標開啟期間跨事務。NOWAIT/WAIT/SKIP LOCKED 11g+ 全支援,10g 僅支援 NOWAIT。DISTINCT/GROUP BY/UNION 等導致不可更新,會報 ORA-02014。INSERT/UPDATE/DELETE 隱含行級鎖 (TX),效果等同 FOR UPDATE,但 SELECT FOR UPDATE 可提前鎖定、延後修改,實現樂觀離線鎖或長事務拆分。
掌握四種等待模式與 OF 子句,行級鎖成為併發控制的精準手術刀。