當需要在游標遍歷過程中對「當前行」執行UPDATE/DELETE操作時,標準SQL的WHERE條件重複編寫不僅繁瑣,且難以保證與游標查詢條件完全一致。Oracle提供FOR UPDATE + WHERE CURRENT OF機制,實現精準的當前行鎖定與修改。
CURSOR cursor_name IS
SELECT ...
FROM ...
FOR UPDATE [OF [schema.]table.column[, ...]] [NOWAIT];
關鍵行為:
OF子句:多表連接時指定鎖定特定表,省略則鎖定所有涉及表NOWAIT:遇鎖立即報錯(ORA-00054),不等待UPDATE table_name
SET column = value
WHERE CURRENT OF cursor_name;
DELETE FROM table_name
WHERE CURRENT OF cursor_name;
精準定位游標最近一次FETCH返回的行,無需重複WHERE條件。
DECLARE
CURSOR c1 IS
SELECT empno, sal, comm
FROM emp
WHERE comm IS NULL
FOR UPDATE OF comm; -- 關鍵:鎖定comm欄位所在行
v_comm NUMBER(10,2);
BEGIN
FOR r1 IN c1 LOOP -- 隱式OPEN/FETCH/CLOSE
IF r1.sal < 500 THEN
v_comm := r1.sal * 0.25;
ELSIF r1.sal < 1000 THEN
v_comm := r1.sal * 0.20;
ELSIF r1.sal < 3000 THEN
v_comm := r1.sal * 0.15;
ELSE
v_comm := r1.sal * 0.12;
END IF;
UPDATE emp
SET comm = v_comm
WHERE CURRENT OF c1; -- 精準更新當前行
END LOOP;
COMMIT; -- 釋放鎖定
END;
| 項目 | 說明 | 注意事項 |
|---|---|---|
| 鎖定時機 | OPEN游標時刻 | 非宣告時、非FETCH時 |
| 鎖定範圍 | 結果集所有行 | 大結果集慎用,考慮分批處理 |
| 鎖模式 | Row Exclusive (RX) | 允許並發查詢,阻塞DML與SELECT FOR UPDATE |
| 釋放時機 | COMMIT/ROLLBACK | 游標CLOSE不釋放鎖,必須結束事務 |
| NOWAIT建議 | 高併發核心業務建議加上 | 避免無限期阻塞,捕獲ORA-00054重試 |
CURSOR c_emp_dept IS
SELECT e.empno, e.sal, d.deptno
FROM emp e, dept d
WHERE e.deptno = d.deptno
AND e.comm IS NULL
FOR UPDATE OF e.comm; -- 僅鎖定emp表的comm欄位行
DECLARE
CURSOR c1 IS SELECT empno, sal FROM emp WHERE comm IS NULL FOR UPDATE OF comm NOWAIT;
v_comm NUMBER;
v_cnt NUMBER := 0;
BEGIN
FOR r1 IN c1 LOOP
v_comm := CASE
WHEN r1.sal < 1000 THEN r1.sal * 0.2
ELSE r1.sal * 0.1
END;
UPDATE emp SET comm = v_comm WHERE CURRENT OF c1;
v_cnt := v_cnt + 1;
IF MOD(v_cnt, 100) = 0 THEN -- 每100行提交一次
COMMIT;
-- 重新開啟游標繼續處理(需重新查詢未處理行)
END IF;
END LOOP;
COMMIT;
END;
注意:COMMIT後游標失效,分批處理需重新開啟游標或使用主鍵記錄進度。
DECLARE
CURSOR c1 IS SELECT empno, sal FROM emp WHERE comm IS NULL FOR UPDATE OF comm NOWAIT;
BEGIN
FOR r1 IN c1 LOOP
BEGIN
-- 業務邏輯
UPDATE emp SET comm = r1.sal * 0.1 WHERE CURRENT OF c1;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK; -- 釋放鎖定
LOG_ERROR(r1.empno, SQLERRM);
END;
END LOOP;
COMMIT;
END;
UPDATE ... WHERE ...)或MERGE語句,僅在需逐行複雜邏輯時使用游標FOR UPDATE + WHERE CURRENT OF是處理「游標遍歷+當前行修改」的標準解法。核心要點:宣告時加FOR UPDATE、DML用WHERE CURRENT OF、事務結束釋放鎖、大數據量分批處理、異常分支必須ROLLBACK。實務中權衡併發影響,優先考慮集合操作替代逐行游標。