2012-11-21 66 views
2

在下面的PL/SQL代碼中,TABLE_ONE保存表名tname,列名cname和rowid rid。 For循環從TABLE_ONE獲取記錄,並更新表tname中的列cname,以獲得行id爲rid的記錄。但是如果在tname中更新的記錄被鎖定,那麼for循環會卡住,並且不會處理來自TABLE_ONE的其他記錄。理想情況下,腳本忽略更新失敗的記錄並繼續進行。請告知可能是什麼問題。PL/SQL在循環內執行立即異常處理

BEGIN 
    FOR c IN (SELECT * FROM TABLE_ONE a) 
    LOOP 
     DECLARE 
      TNAME varchar2(30); 
      CNAME varchar2(30); 
      RID ROWID; 
      X number; 
      updt_stmt varchar2(300); 
     BEGIN 
      BEGIN 
      TNAME := c.TNAME; 
      CNAME := c.CNAME; 
      RID := c.RID;     
      DBMS_OUTPUT.PUT_LINE(TNAME || '=>' || CNAME); 
      updt_stmt := 'UPDATE ' || TNAME || ' SET ' || CNAME || ' = ''123'' WHERE ROWID like ''%' || RID || '%''';     
      EXECUTE IMMEDIATE updt_stmt; 

      EXCEPTION 
      WHEN OTHERS THEN 
      DBMS_OUTPUT.PUT_LINE('ERROR'); 

      END; 
     END; 
    END LOOP; 
END; 

回答

1

未經檢驗的,但我認爲你可以先嚐試鎖定與FOR UPDATE記錄,並通過指定NOWAIT導致失敗,如果其他一些交易活躍。然後你可以捕獲這個異常並跳過處理。這是一個未經測試的例子:

DECLARE 
    x ROWID; 
    resource_busy EXCEPTION; 
    PRAGMA EXCEPTION_INIT(resource_busy, 
         -00054); 
BEGIN 
    FOR c IN (SELECT * 
       FROM table_one a) 
    LOOP 
    DECLARE 
     tname  VARCHAR2(30); 
     cname  VARCHAR2(30); 
     rid  ROWID; 
     x   NUMBER; 
     updt_stmt VARCHAR2(300); 
    BEGIN 
     BEGIN 
     tname := c.tname; 
     cname := c.cname; 
     rid := c.rid; 
     dbms_output.put_line(tname || '=>' || cname); 

     BEGIN 
      EXECUTE IMMEDIATE 'SELECT rowid FROM ' || tname || 
          ' WHERE rowid = :x FOR UPDATE NOWAIT' 
      INTO x 
      USING rid; 
     EXCEPTION 
      WHEN resource_busy THEN 
      dbms_output.put_line('Record locked; try again later.'); 
      CONTINUE; 
     END; 

     updt_stmt := 'UPDATE ' || tname || ' SET ' || cname || 
        ' = ''123'' WHERE ROWID like ''%' || rid || '%'''; 
     EXECUTE IMMEDIATE updt_stmt; 

     EXCEPTION 
     WHEN OTHERS THEN 
      dbms_output.put_line('ERROR'); 

     END; 
    END; 
    END LOOP; 
END;