17

如果我正在编写 SQL Server (2008r2) 过程,并将其包装在事务中,是否需要将其显式包含在 try..catch 块中,然后在 catch 块中显式调用回滚,或者它会退出并自己回滚一样吗?

IE:

这是如何做到的:

    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

感谢您的任何帮助。

4

3 回答 3

19

您的问题的答案取决于SET XACT_ABORT设置:

指定当 Transact-SQL 语句引发运行时错误时 SQL Server 是否自动回滚当前事务。

当 SET XACT_ABORT 为 ON 时,如果 Transact-SQL 语句引发运行时错误,则整个事务将终止并回滚。

当 SET XACT_ABORT 为 OFF 时,在某些情况下,只有引发错误的 Transact-SQL 语句被回滚并且事务继续处理。根据错误的严重程度,即使 SET XACT_ABORT 为 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 的情况,您可能需要在错误发生时做一些特殊的事情。如果是这样,不要忘记尝试/捕获异常处理:

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
于 2012-06-08T14:04:01.693 回答
4

如果在大多数情况下出现错误,回滚将自动发生,但不是全部

如果您想保证在开始事务之前使用 SET XACT_ABORT ON 回滚所有错误

最佳实践是使用 try-catch 块明确地捕获错误并在那里采取行动,可能包括回滚和报告/记录错误。

于 2012-06-08T13:59:11.883 回答
0

这取决于错误的严重程度。足够高——也许是16?-- 该过程可能会在失败的线路处停止,从而使交易保持打开状态并锁定到位。如果事务中有任何出错的机会,您肯定希望将其包装在 try-catch 块中,就像您在第一个示例中所做的那样。

于 2012-06-08T14:00:13.507 回答