今天和写存储过程的同事为事务处理问题有点争论,请大家一起来讨论讨论。
存储过程:
过程A
{
...
Update ...
...
Update ..
...
}
程序:
调用存储过程A();这里存在一个事务问题,大家觉得应该应该把代码改造成:
开始事务;
调用存储过程A;
提交事务。
错误时回滚事务;还是存储过程内部应该有事务处理自己的回滚,即
过程A
{
开始事务
...
Update ...
...
Update ..
...
没有错误提交事务
有错误回滚事务
}
两种方式都能解决问题,不过大家来讨论一下哪种方式更规范,如果能说出为什么最好.
(注意,这是只调一个过程的情况,调多个过程的话程序里肯定要事务处理,这个不用讨论。)个人觉得存储过程自己应该处理好自己内部的错误(包括逻辑错误),做好事务回滚.
程序里的事务是用来处理多个过程调用情况下,后面的过程执行有问题,回滚前面的过程的.

解决方案 »

  1.   

    关键看你调用过程的程序里是否还有其他DML,而这些DML是否和存储过程里的事务属于同一事务。
    如果要求程序里其他的DML和过程要么同时成功,要么同时失败(回退),那么,放程序里比较合适。
    如果不需要,也就是不属于同一事务,那么,过程里处理错误也行。
      

  2.   

    我就是指从单个存储过程来说,内部有多个update的,是自己处理好事务,还是要调用的人根据返回的执行结果来提交或者回滚事务。
      

  3.   

    我没有星星啊,只是支持一下
    Thomas kyte大师有这样的名:
    • You should do it in a single SQL statement if at all possible.
    • If you cannot do it in a single SQL statement, then do it in PL/SQL (but as little PL/SQL as possible!).
    • If you cannot do it in PL/SQL (due to some missing feature like listing the files in a directory), try a Java stored procedure. This is an extremely rare need today with Oracle9i and above.
    • If you cannot do it in Java, do it in a C external procedure. This is most frequently the approach when raw speed or the use of a third-party API written in C is needed.
    • If you cannot do it in a C external routine, you might want to think seriously about why exactly you need to do it.所以,占成把事务尽可能放入存储过程去处理,这样可以更好异常处理及维护和调试存储过程。
      

  4.   

    只一过程,自然是过程里判断,根据执行情况来决定提交或回滚。这样一来,过程书写就稍微麻复杂点,主要是翻译ORACLE错误为程序异常。我明白了,程序开发和数据库开发,都想省事,呵呵。反正这异常总得有人捕捉,至于到底谁干这事,还得商量着来办。
      

  5.   

    过程A
    {
    开始事务
    ...
    Update ...
    ...
    Update ..
    ...
    --没有错误提交事务   --我觉得commit由java执行比较好,便于以后存储过程B调用A
    有错误回滚事务
    }
      

  6.   

    To codearts:
    如果外面还要调用过程B的,而且需要在一个事务里做的话,程序里会开始一个事务的。这时候存储过程A里的Commit应该只是内部事务的Commit,仍然受外层的事务控制的吧?
    我理解为一个方法应该自己做好自己的事情,自己内部已经出错了,不处理回滚,而依赖调用者,是不是有点不合理?
      

  7.   

    另外,感觉存储过程修改和调试远比JAVA来得爽快,JAVA修改一下就要编译一下,又要打一个包,如果服务很多,那么全部要发布,并且重启WEBSERVER,如果正式上线运行了,变更就麻烦了(现在我的情况就是这样,启动一次TOMCAT至少3四分钟,并且100多台啊,不能一次性全部重启,也就是不能断业务)。反之,oracle调试,修改,编译,一切大功告成!!
      

  8.   


    不对, 你说的这个是SQL Server的嵌套事务, Oracle里没有这个东西。 Oralce里有自治事务,但没有类似于SQL Server里的嵌套事务。 所以我认为,存储过程里不做COMMIT为好。 除非此过程功能比较独立
      

  9.   

    begin
      p_a;    --如果p_a里有commit;
      p_b;    --p_b中rollback, p_a的commit是不能回滚的,也就是事务不完整了
    end;
      
      

  10.   

    众说纷纭啊。
    算了,程序里加上事务吧。
    不过我还是觉得不合理,本来存储过程自己可以做的事,现在所有调用的地方都得先开始事务-〉调用过程-〉结束事务,工作量明显增加。作为公用方法,调用的地方肯定不止一个。
    至少我看到SqlServer里的系统存储过程都会有事务去处理自己对库的改变的,不知道其他数据库是不是这样。
    To codearts:
    Oracle不支持下面这种嵌套事务?以前一直做SqlServer,确认不知道。
    begin
    开始大事务
    p_a; --如果p_a里有commit;
    p_b; --p_b中rollback, p_a的commit是不能回滚的,也就是事务不完整了
    提交或回滚内部所有事务
    end;
      

  11.   

    To codearts:
    查了一下,Oracle应该也是支持嵌套(我看到人家提到SavePoint之类的)。至于自治事务和我们讨论的问题没有关系,只是为了实现独立于外层事务的独立事务,不受外部事务的提交和回滚影响。
      

  12.   

    begin
    开始大事务     --本身DML就是开启事务的,没有开启大事务这回事
    p_a;          --如果这里commit,事务就提交了
    p_b;          --这里又是一个新的事务了
    提交或回滚内部所有事务  --提交或回滚的是p_b开始的事务
    end;--sql server就可以这样
    begin tran a
    do something ....
    begin tran b
    do something ...
    commit b;
    rollback a;    --这里回滚后,事务B也回滚了。 这就是嵌套事务,ORACLE没有这个东西