Oracle 採用先進先出 (FIFO) 的鎖排隊機制。當 Session 請求的鎖被其他 Session 持有,該 Session 進入等待隊列。唯一避免排隊等待的方法是使用 SELECT ... FOR UPDATE 搭配 NOWAIT 或 WAIT n 子句。本文深度解析鎖排隊原理、FOR UPDATE 進階用法、與 SQL Server 鎖提示的對比。
ENQ: TX - ROW LOCK CONTENTION 等待事件SELECT ... FROM table WHERE condition FOR UPDATE [OF column_list] [NOWAIT | WAIT n | SKIP LOCKED];
| 子句 | 行為 | 適用場景 |
|---|---|---|
| 無子句 | 像 DML 一樣排隊等待,直到獲得鎖 | 必須獲取鎖才能繼續的業務 |
| NOWAIT | 立即返回 ORA-00054,不等待 | 高併發搶單、秒殺、非關鍵路徑嘗試鎖定 |
| WAIT n | 最多等待 n 秒,超時返回 ORA-30006 | 允許短暫等待,避免無限阻塞 |
| SKIP LOCKED (11g+) | 跳過已鎖定行,僅鎖定可用行 | 佇列消費者模式、批次處理避開熱點行 |
-- 嘗試鎖定訂單,最多等 3 秒
SELECT order_id, status FROM orders WHERE order_id = 1001 FOR UPDATE WAIT 3;
-- 秒殺場景:立即失敗而不阻塞
SELECT * FROM inventory WHERE product_id = 999 AND qty > 0 FOR UPDATE NOWAIT;
| 提示 | 行為 | Oracle 對應 |
|---|---|---|
NOLOCK | 髒讀,忽略共享鎖,可能讀到未提交資料 | 無直接對應 (Oracle 採用 MVCC,讀不阻塞寫) |
UPDLOCK | 讀取時加更新鎖,持有至事務結束 | SELECT ... FOR UPDATE |
ROWLOCK | 強制行級鎖,防止升級為頁/表鎖 | Oracle 預設即行級鎖,無升級機制 |
核心差異:Oracle 讀寫不互斥(多版本並發控制 MVCC),SELECT 不加鎖;SQL Server 預設讀取加共享鎖,需 NOLOCK 避免阻塞但犧牲一致性。
SELECT * FROM task_queue WHERE status='PENDING' FOR UPDATE SKIP LOCKED 實現高併發任務分發V$SESSION_WAIT、V$LOCK、DBA_BLOCKERS 定位阻塞鏈理解鎖排隊邏輯,靈活運用 FOR UPDATE 變體,是構建高併發、低延遲 Oracle 應用的關鍵技能。