如果存在回滚,为什么这些嵌套的 SQL 服务器事务会抛出不匹配错误?

Why are these nested SQL Server transactions throwing a mismatch error if there is a rollback?

运行 'Test Errors' 我得到了意想不到的结果。我认为通过检查 @@Trancount 可以避免不匹配。任何人都可以帮助我更好地回滚错误吗?我想回滚所有嵌套的事务。存储过程既可以嵌套也可以独立。

alter procedure TestErrors
as
begin
    begin try
        begin transaction

        exec TestErrorsInner;

        IF @@TRANCOUNT > 0
            commit transaction;
    end try
    begin catch
        IF @@TRANCOUNT > 0
            rollback transaction;
        select ERROR_MESSAGE();
    end catch
end

alter procedure TestErrorsInner
as
begin
    begin try
        begin transaction

        RAISERROR('Test Error',16,1);

        IF @@TRANCOUNT > 0
            commit transaction;
    end try
    begin catch
        IF @@TRANCOUNT > 0
            rollback transaction;
        select ERROR_MESSAGE();
    end catch
end

结果:

Test Error

Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.

这是因为您在 TestErrors 中捕获了一个未处于活动状态的事务。

您已经在 TestErrorsInnerCatch 个区块中回滚了您的交易。 然后你又试图在TestErrors中做COMMIT/ROLLBACK。所以它抛出一个错误。

您有责任在 TestErrorsInnerCatch 块中再次明确提出错误。因此该错误将成为父 SP 的输入。

所以你的 TestErrorsInner 应该像

ALTER PROCEDURE TESTERRORSINNER
AS
BEGIN
    BEGIN TRY
        BEGIN TRANSACTION

        RAISERROR('TEST ERROR',16,1);

        IF @@TRANCOUNT > 0
            COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
        --SELECT ERROR_MESSAGE();
         RAISERROR('TEST ERROR in Catch',16,1);  --Here Raised 
    END CATCH
END

现在执行TestErrors存储过程,你不会得到那个错误。

并且您可以使用XACT_STATE()

查看交易状态

调用 XACT_STATE() 将给出 0 或 1 或 -1 的结果(来自 MSDN

  • 如果为 1,事务是可提交的。
  • 如果为 -1,事务不可提交,应该回滚。
  • if XACT_STATE = 0 表示没有事务,提交或回滚操作会产生错误。