今天和写存储过程的同事为事务处理问题有点争论,请大家一起来讨论讨论。
存储过程:
过程A
{
...
Update ...
...
Update ..
...
}
程序:
调用存储过程A();这里存在一个事务问题,大家觉得应该应该把代码改造成:
开始事务;
调用存储过程A;
提交事务。
错误时回滚事务;还是存储过程内部应该有事务处理自己的回滚,即
过程A
{
开始事务
...
Update ...
...
Update ..
...
没有错误提交事务
有错误回滚事务
}
两种方式都能解决问题,不过大家来讨论一下哪种方式更规范,如果能说出为什么最好.
(注意,这是只调一个过程的情况,调多个过程的话程序里肯定要事务处理,这个不用讨论。)个人觉得存储过程自己应该处理好自己内部的错误(包括逻辑错误),做好事务回滚.
程序里的事务是用来处理多个过程调用情况下,后面的过程执行有问题,回滚前面的过程的.
存储过程:
过程A
{
...
Update ...
...
Update ..
...
}
程序:
调用存储过程A();这里存在一个事务问题,大家觉得应该应该把代码改造成:
开始事务;
调用存储过程A;
提交事务。
错误时回滚事务;还是存储过程内部应该有事务处理自己的回滚,即
过程A
{
开始事务
...
Update ...
...
Update ..
...
没有错误提交事务
有错误回滚事务
}
两种方式都能解决问题,不过大家来讨论一下哪种方式更规范,如果能说出为什么最好.
(注意,这是只调一个过程的情况,调多个过程的话程序里肯定要事务处理,这个不用讨论。)个人觉得存储过程自己应该处理好自己内部的错误(包括逻辑错误),做好事务回滚.
程序里的事务是用来处理多个过程调用情况下,后面的过程执行有问题,回滚前面的过程的.
如果要求程序里其他的DML和过程要么同时成功,要么同时失败(回退),那么,放程序里比较合适。
如果不需要,也就是不属于同一事务,那么,过程里处理错误也行。
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.所以,占成把事务尽可能放入存储过程去处理,这样可以更好异常处理及维护和调试存储过程。
{
开始事务
...
Update ...
...
Update ..
...
--没有错误提交事务 --我觉得commit由java执行比较好,便于以后存储过程B调用A
有错误回滚事务
}
如果外面还要调用过程B的,而且需要在一个事务里做的话,程序里会开始一个事务的。这时候存储过程A里的Commit应该只是内部事务的Commit,仍然受外层的事务控制的吧?
我理解为一个方法应该自己做好自己的事情,自己内部已经出错了,不处理回滚,而依赖调用者,是不是有点不合理?
不对, 你说的这个是SQL Server的嵌套事务, Oracle里没有这个东西。 Oralce里有自治事务,但没有类似于SQL Server里的嵌套事务。 所以我认为,存储过程里不做COMMIT为好。 除非此过程功能比较独立
p_a; --如果p_a里有commit;
p_b; --p_b中rollback, p_a的commit是不能回滚的,也就是事务不完整了
end;
算了,程序里加上事务吧。
不过我还是觉得不合理,本来存储过程自己可以做的事,现在所有调用的地方都得先开始事务-〉调用过程-〉结束事务,工作量明显增加。作为公用方法,调用的地方肯定不止一个。
至少我看到SqlServer里的系统存储过程都会有事务去处理自己对库的改变的,不知道其他数据库是不是这样。
To codearts:
Oracle不支持下面这种嵌套事务?以前一直做SqlServer,确认不知道。
begin
开始大事务
p_a; --如果p_a里有commit;
p_b; --p_b中rollback, p_a的commit是不能回滚的,也就是事务不完整了
提交或回滚内部所有事务
end;
查了一下,Oracle应该也是支持嵌套(我看到人家提到SavePoint之类的)。至于自治事务和我们讨论的问题没有关系,只是为了实现独立于外层事务的独立事务,不受外部事务的提交和回滚影响。
开始大事务 --本身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没有这个东西