我是否需要在SQL Server过程中使用try..catch块和显式回滚?

时间:2012-06-08 13:53:38

标签: sql-server sql-server-2008

如果我正在编写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

感谢您的帮助。

3 个答案:

答案 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块中,就像您在第一个示例中所做的那样。