具有嵌套事务的SQL Try/Catch逻辑

kat*_*roh 3 t-sql sql-server nested-transactions sql-server-2008 sqltransaction

下面的sproc是根据本文中的模板实现的:异常处理和嵌套事务.这个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
Run Code Online (Sandbox Code Playgroud)

Rem*_*anu 5

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

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

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

死锁总是会导致无法进行的交易.实际上,在死锁的情况下,当你捕获死锁异常时,事务已经作为死锁牺牲品回滚.