PLSQL 异常中的回滚

Posted

技术标签:

【中文标题】PLSQL 异常中的回滚【英文标题】:Rollback in PLSQL Exception 【发布时间】:2012-01-04 06:46:18 【问题描述】:

想知道当检测到SQL异常(其他时异常)时是否需要回滚:

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;

【问题讨论】:

我会在 Oracle 的 Implicit Rollbacks 上阅读 Tom Kyte。 SQL*Plus 是另一种动物,您可以明确告诉它自动提交任何一组语句。 【参考方案1】:

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

至于是否需要回滚更改,则视情况而定。

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

通常,您只会将事务控制语句放在代码的最外层块中。由于过程中的COMMITROLLBACK 提交或回滚会话中完成的任何工作,无论它是否由过程完成,因此您在添加事务控制语句时要非常谨慎。您通常希望让调用者决定是提交还是回滚。当然,仅此而已——最终,您将处于最外层的块中,永远不会被其他例程调用,并且您需要有适当的事务控制——但这是非常谨慎的事情关于你是否正在编写可能被重用的代码。

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

【讨论】:

以上是关于PLSQL 异常中的回滚的主要内容,如果未能解决你的问题,请参考以下文章

Spring transactions - 新事务中的异常导致父事务中的回滚

Mule请求响应VM的回滚异常策略

jfinal的回滚

简单事务的回滚

如何撤消 TFS 中的回滚?

Mercurial Eclipse 插件中的回滚、回退和剥离有啥区别?