3

下面的存储过程是按照本文中的模板实现的:异常处理和嵌套事务。这个sproc应该处理死锁,它被另一个已经创建事务的sproc调用。内部事务的 BEGIN/COMMIT 的一些魔法不匹配,因为我得到了这个异常:Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0. 据我了解, catch 被执行,@xstate = -1是真的,整个外部事务被回滚。

发生不匹配的任何想法?

CREATE PROCEDURE [dbo].[mysproc]
AS
BEGIN
    SET NOCOUNT ON;
    SET DEADLOCK_PRIORITY LOW;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;  

    BEGIN TRY        
        DECLARE @trancount int;
        SET @trancount = @@TRANCOUNT;        
        IF (@trancount = 0)
            BEGIN TRANSACTION;
        ELSE
            SAVE TRANSACTION InnerTran;   
        --              
        -- do some work that can potentially cause a deadlock
        --
   END TRY
   BEGIN CATCH
        DECLARE @xstate int
        SELECT @xstate = XACT_STATE()

        IF (@xstate = - 1)
            ROLLBACK;
        IF (@xstate = 1 and @trancount = 0)
            ROLLBACK;
        IF (@xstate = 1 and @trancount > 0)
            ROLLBACK TRANSACTION InnerTran;
   END CATCH  
END
GO
4

1 回答 1

5

不同之处在于您不会引发异常。如果XACT_STATE()在 catch 块中为 -1(即不可提交的事务,就像死锁会导致)在这种情况下,您的过程将回滚(它必须,它在 -1 情况下没有选择)但返回而不会引发异常. 因此,不匹配。您必须引发异常并在调用者中捕获它。

请参阅不可提交的事务和 XACT_STATE

如果 TRY 块中产生的错误导致当前事务的状态无效,则该事务被归类为不可提交事务。当错误发生在 TRY 块内时,通常在 TRY 块外结束事务的错误会导致事务进入不可提交状态。不可提交的事务只能执行读取操作或 ROLLBACK TRANSACTION。该事务不能执行任何会生成写操作或 COMMIT TRANSACTION 的 Transact-SQL 语句。如果事务已被归类为不可提交事务,则 XACT_STATE 函数返回值 -1。

死锁总是会导致无法提交的事务。事实上,在死锁的情况下,当你捕捉到死锁异常时,事务已经作为死锁牺牲品回滚了。

于 2011-12-14T20:53:02.530 回答