2011-11-22 75 views
3

想知道是否需要回滚时,SQL异常检测(当别人除外):回滚在PLSQL异常

declare 
cursor c_test is 
    select * 
    from tesing; 
    begin 
     for rec in c_test loop 
     begin 
      update test1 set test1.name=rec.name where test1.id=rec.id; 
      IF sql%rowcount = 1 THEN 
          commit; 
      ELSIF sql%rowcount =0 THEN 
        dbms_output.put_line('No Rows Updated'); 
      else 
        dbms_output.put_line('More than 1 row exists'); 
        rollback; 
      END IF; 
     exception when others then 
        dbms_output.put_line(Exception'); 
        rollback; 
     end;  

end; 
+2

我会在Oracle中阅读Tom Kyte的[Implicit Rollbacks](http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:43818437682131)。 SQL * Plus是一种不同的动物,您可以专门告诉它自动提交任何一组语句。 –

+0

非常感谢信息 – Arav

回答

15

首先,我假设我们可以忽略语法错误(例如,没有END LOOPdbms_output.put_line呼叫缺少第一个单引号等)

至于是否有必要回滚更改,取决于。

通常,您不会有临时提交循环。这通常是一个糟糕的架构,因为它在I/O和经过时间方面成本更高。这也使编写可重启代码变得更加困难。例如,如果您的SELECT语句选择了10行,则会发出(并提交)5个更新,然后第6个更新失败?在修复异常之后,能够重新启动第6行的唯一方法是在单独的表中存储(并更新)代码的进度。它也为任何调用这个块的代码产生了问题,这个代码块必须处理一半的工作已经完成(并且已经提交),另一半没有完成。

通常,您只会将事务控制语句放在代码的最外面的块中。由于过程中的COMMITROLLBACK提交或回滚会话中完成的任何工作,而不管它是否由过程完成,所以您希望对添加事务控制语句非常谨慎。您通常希望让调用者决定是否提交或回滚。当然,只有这样才行 - 最终,你将会进入最不受其他程序调用的最外层块,并且你需要有适当的事务控制 - 但是要非常谨慎关于你是否正在编写可能被重用的代码。

在这种情况下,由于您有临时提交,所以ROLLBACK的唯一影响是如果第一个更新语句失败,那么在调用此块之前在会话中完成的工作将被回滚。如果第一个更新语句成功,临时提交将会提交以前的更改。这是人们担心的一种副作用,当他们谈论为什么临时提交和可重用块中的事务控制有问题时。

+0

非常感谢您的信息 – Arav