Oracle PL / SQL在循环中捕获锁定异常并继续

时间:2016-11-28 02:26:02

标签: oracle exception plsql cursor locked

我有一个程序,循环通过游标做一些逻辑。我已经在光标上放置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异常,因此,程序刚刚终止而没有继续循环遍历游标。

有人能给我一些建议吗?非常感谢

1 个答案:

答案 0 :(得分:2)

打开游标进行更新时,此语句适用于场景:首先运行选择查询并为所有记录设置锁定,之后执行 fetch < / em> operations。

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;