3

次の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 = -1trueであり、外部トランザクション全体がロールバックされます。

不一致が発生するアイデアはありますか?

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

違いは、例外を発生させないことです。キャッチブロックで-1の場合XACT_STATE()(つまり、デッドロックが発生するようなコミットできないトランザクション)このような場合、プロシージャはロールバックします(-1の場合は選択できません)が、例外を発生させずに戻ります。したがって、不一致。例外を発生させて、呼び出し元でキャッチする必要があります。

Uncommittable TransactionsおよびXACT_STATEを参照してください:

TRYブロックで生成されたエラーにより、現在のトランザクションの状態が無効になる場合、そのトランザクションはコミット不可能なトランザクションとして分類されます。通常、TRYブロックの外部でトランザクションを終了するエラーにより、TRYブロックの内部でエラーが発生すると、トランザクションはコミット不可能な状態になります。コミットできないトランザクションは、読み取り操作またはロールバックトランザクションのみを実行できます。トランザクションは、書き込み操作またはCOMMITTRANSACTIONを生成するTransact-SQLステートメントを実行できません。XACT_STATE関数は、トランザクションがコミット不可能なトランザクションとして分類されている場合、値-1を返します。

デッドロックは常に不適合なトランザクションになります。実際、デッドロックの場合、デッドロック例外をキャッチするまでに、トランザクションはすでにデッドロックの犠牲者としてロールバックされています。

于 2011-12-14T20:53:02.530 に答える