如果我正在编写SQL Server(2008r2)过程,并将其包装在事务中,是否需要将其显式地封装在try..catch块中,然后在catch块中显式调用rollback,或者将它自己退出并回滚它?
即:
这是怎么回事:
begin transaction
begin try
delete from....
insert into...
end try
begin catch
rollback transaction
return
end catch
commit transaction
与:比较:
begin transaction
delete from....
insert into...
commit transaction
感谢您的帮助。
答案 0 :(得分:19)
您的问题的答案取决于SET XACT_ABORT
设置:
指定SQL Server是否自动回滚当前 Transact-SQL语句引发运行时错误时的事务。
当SET XACT_ABORT为ON时,如果Transact-SQL语句引发了 运行时错误,整个事务终止并回滚。
当SET XACT_ABORT为OFF时,在某些情况下只有Transact-SQL 引发错误的语句将回滚并进行事务处理 继续处理。根据错误的严重程度, 即使SET XACT_ABORT为OFF,整个事务也可以回滚。 OFF是默认设置。
编译错误(例如语法错误)不受SET的影响 XACT_ABORT。
例如,尝试以下代码。第一个除以0会引发错误,但继续执行。第二次除以零会引发错误,手停止执行:
begin transaction
set xact_abort off
select 1 / 0 -- causes divide by zero error, but continues
select @@trancount -- returns 1
set xact_abort on
select 1 / 0 -- causes divide by zero error and terminates execution
select @@trancount -- we never get here
rollback
如果XACT_ABORT为ON,则错误将中止事务,并且您不需要TRY / CATCH。
如果XACT_ABORT为OFF,您需要检查每个语句的状态以查看是否发生错误:
begin transaction
delete from...
if @@error <> 0
begin
if @@trancount > 0
rollback
return
end
insert into...
if @@error <> 0
begin
if @@trancount > 0
rollback
return
end
commit
但是,如果您发现需要TRY / CATCH的情况,则可能需要在发生错误时执行一些特殊操作。如果是这样,请不要忘记TRY / CATCH异常处理:
begin transaction
set xact_abort on
begin try
select 1 / 0 -- causes divide by zero error and terminates execution
select @@trancount -- we never get here
commit
end try
begin catch
select xact_state() -- this will be -1 indicating you MUST rollback before doing any other operations
select @@trancount -- this will probably be one, because we haven't ended the transaction yet
if xact_state() <> 0
begin try
select 'rollback'
rollback
-- do something to handle or record the error before leaving the current scope
select 'exception processing here'
--insert into...
end try
begin catch
-- ignore rollback errors
end catch
end catch
答案 1 :(得分:4)
如果你想保证在使用SET XACT_ABORT ON的开始事务之前回滚所有错误
最佳做法是使用try-catch块明确捕获错误并在那里采取措施,包括回滚和报告/记录错误。
答案 2 :(得分:0)
这取决于错误的严重性级别。足够高 - 16,也许? - 流程可能会在失败的行停止,使事务打开并锁定到位。如果事务中存在任何错误的可能性,您肯定希望将其包装在try-catch块中,就像您在第一个示例中所做的那样。