web-dev-qa-db-ja.com

内部プロシージャはロールバックされますが、外部プロシージャはまだコミットされています

私は5つの異なる内部プロシージャを呼び出すような外部プロシージャを持っています

Parent procedure(Tran/try/catch)
Inner sp1 (Tran/try/catch)
'
'
Inner sp5 (Tran/try/catch)

ただし、この場合、内部プロシージャの1つがロールバックされても、外部プロシージャにはエラーがないため、プロシージャはコミットされます。この問題を解決するにはどうすればよいですか?ありがとう!!

すみません。コードは次のようになります。--INNER PROCEDURE

CREATE PROC spInner
AS
BEGIN

DECLARE @transactioncount INT
SET @transactioncount = @@TRANCOUNT

IF (@transactioncount > 0)
BEGIN


SAVE TRANSACTION savepoint1
END
ELSE
BEGIN
    BEGIN TRANSACTION

BEGIN TRY
    DROP TABLE IF EXISTS #temp
    CREATE TABLE #temp (id INT NOT NULL)
    INSERT INTO #temp (id)
    SELECT NULL
    INSERT INTO #temp (id)
    SELECT 1
    INSERT INTO #temp (id)
    SELECT 'A'

IF (@transactioncount = 0)
BEGIN
    COMMIT TRANSACTION          
END

END TRY
BEGIN CATCH

IF (@transactioncount = 0)
BEGIN
    ROLLBACK TRANSACTION        
END
ELSE IF (XACT_STATE() <> -1)
BEGIN
    ROLLBACK TRANSACTION savepoint1         
END

    --logs errors into Error Log table
PRINT ERROR_MESSAGE()
END CATCH
END

-外側の手順

CREATE PROC spOuter
AS
BEGIN

DECLARE @transactioncount INT
SET @transactioncount = @@TRANCOUNT

IF (@transactioncount > 0)
BEGIN
    SAVE TRANSACTION savepoint2
END
ELSE
BEGIN
    BEGIN TRANSACTION

BEGIN TRY

    Exec dbo.spInner

        IF (@transactioncount = 0)
    BEGIN
        COMMIT TRANSACTION  
    END

END TRY
BEGIN CATCH

    IF (@transactioncount = 0)
    BEGIN
        ROLLBACK TRANSACTION        
    END
    ELSE IF (XACT_STATE() <> -1)
    BEGIN
        ROLLBACK TRANSACTION savepoint2         
    END

        --logs errors into Error Log table
    PRINT ERROR_MESSAGE()
END CATCH

END      

この場合、内部プロシージャでエラーが発生しても、内部プロシージャでキャッチされたエラーは外部プロシージャではキャッチされず、外部プロシージャがコミットされます。

4
user186949

あなたが直面している問題は、TRY ... CATCHコンストラクトがエラーを処理する方法にあります-エラーを消費し、食べて、戻りコード0以外は何も吐き出しません。これは docs on TRY ... CATCH の非常に無害な行で示されています

CATCHブロックによってトラップされたエラーは、呼び出し元のアプリケーションには返されません。エラー情報の一部をアプリケーションに返す必要がある場合、CATCHブロックのコードは、SELECT結果セットやRAISERRORおよびPRINTステートメントなどのメカニズムを使用して返す必要があります。

ただし、この行は古くなっているようで、THROWステートメントに関する情報はありません。

この問題を解決するには、 throwステートメント を使用して、ロールバックイベントの後に問題のあるエラーを再スローできます このフィドル(リンク)で表示 または省略されたサンプル未満:

BEGIN TRY
    BEGIN TRANSACTION

    --Your code goes here

    COMMIT TRANSACTION
END TRY
BEGIN CATCH

    --Some other error handling code here

    ROLLBACK TRANSACTION;

    THROW;

END CATCH

キーはCATCHブロックが何をしているのかを知ることです。TRYブロックでエラーが発生すると、ブロックが消費され(IEが呼び出し元に戻されない)、独自のコードでエラーを処理できるようになります。

あなたの場合、CATCHブロックは単にロールバックを実行するだけです。つまり、エラーが呼び出し元のプロシージャに戻されることはありません。THROWを追加すると、手動でエラーを呼び出し元に返すことによって解決されます(この場合は外部プロシージャ)。

スローを使用したくない場合は、 [〜#〜] raiserror [〜#〜] を使用して、発生するエラーをより詳細に制御することもできます。

4
George.Palacios