Oracle PL/SQL 在循环中捕获锁定异常并继续
Posted
技术标签:
【中文标题】Oracle PL/SQL 在循环中捕获锁定异常并继续【英文标题】:Oracle PL/SQL capture lock exception in loop and continue 【发布时间】:2016-11-28 02:26:01 【问题描述】:我在下面有一个过程,它通过游标循环执行一些逻辑。我已将 FOR UPDATE NOWAIT 放在光标上以锁定我的记录集,以防其他会话中的某人想要更新同一集。
但是可能有这样一种情况,我在光标中选择的记录也被某人锁定了,在这种情况下,我想简单地将锁定的记录记录到日志表中,然后继续到下一条记录循环。
PROCEDURE test(p_id IN NUMBER)
IS
CURSOR cur_test IS
SELECT emp_id,
emp_name
FROM
EMP
FOR UPDATE NOWAIT;
row_locked EXCEPTION;
PRAGMA EXCEPTION_INIT(row_locked, -54);
BEGIN
FOR r_cur_test IN cur_test
LOOP
BEGIN
--do something
EXCEPTION
WHEN row_locked THEN
--log locked record in log table
log_lock('Record is locked');
COMMIT;
END;
END LOOP;
--call log function to log a successful run
COMMIT;
EXCEPTION
WHEN OTHERS THEN
--Unsuccessful completion of the run.Trap all unhandled exceptions.
--log error in error table
log_lock('Process exited with error');
ROLLBACK;
END;
为了测试,我打开会话 1 并执行
select * from EMP FOR UPDATE NOWAIT
在会话 2 中,我执行了
begin
test(1);
end;
它总是进入 OTHERS 异常,因此,procecure 刚刚终止,没有继续循环游标。
谁能给我一些建议?非常感谢
【问题讨论】:
那么,当其他人阻塞时有什么异常?这是一团糟。 光标后面有更多代码for循环,而when others块中的异常就是那个。 那么,有什么例外???如果您无法提供所有相关信息,您希望有人如何帮助您? 您确定在尝试锁定记录时引发了异常。我建议将异常块一起删除一段时间,然后观察引发了什么异常。 @WilliamMu 如果您没有在异常块中隐藏错误消息,您实际上可能有机会调试您的程序。相反,您已经有效地将有用的错误消息信息替换为“哦,发生了错误。不过,我不会告诉您它是什么!”。如果您要将错误消息记录到表中,至少要确保它包含SQLERRM
和/或RAISE
,否则记录发生错误的事实毫无意义。
【参考方案1】:
当您执行 open cursor for update 时,此语句适用于以下场景:首先运行 select 查询并为所有记录设置锁定,然后执行 fetch 操作。
PROCEDURE test(p_id IN NUMBER)
IS
CURSOR cur_test IS
SELECT emp_id,
emp_name,
rowid as row_id
FROM
EMP;
row_locked EXCEPTION;
PRAGMA EXCEPTION_INIT(row_locked, -54);
v_sql varchar2(4000) := 'SELECT 1 FROM EMP t WHERE rowid = :row_id FOR UPDATE NOWAIT';
c int;
n int;
BEGIN
c := dbms_sql.open_cursor;
dbms_sql.parse(c, v_sql, dbms_sql.native);
FOR r_cur_test IN cur_test
LOOP
BEGIN
dbms_sql.bind_variable (c, 'row_id', i.row_id);
n := dbms_sql.execute(c);
--do something
EXCEPTION
WHEN row_locked THEN
--log locked record in log table
log_lock('Record is locked');
COMMIT;
END;
END LOOP;
dbms_sql.close_cursor(c);
--call log function to log a successful run
COMMIT;
EXCEPTION
WHEN OTHERS THEN
--Unsuccessful completion of the run.Trap all unhandled exceptions.
--log error in error table
log_lock('Process exited with error');
dbms_sql.close_cursor(c);
ROLLBACK;
END;
【讨论】:
非常感谢您的详细回答。以上是关于Oracle PL/SQL 在循环中捕获锁定异常并继续的主要内容,如果未能解决你的问题,请参考以下文章
Oracle笔记4-pl/sql-分支/循环/游标/异常/存储/调用/触发器