2

個々のエラーをキャッチしてログに記録するために、複数の TRY/CATCH ブロックを使用する大規模なストアド プロシージャがあります。また、途中でエラーが発生した場合に全体をロールバックできるように、プロシージャの内容全体をトランザクションでラップしました (面倒なクリーンアップを防ぐため)。XACT_ABORT が有効になっているのは、トランザクション全体をロールバックしないためです。

重要なコンポーネント:
私のデータベースには、この手順が実行されるたびにレコードが挿入され、操作の結果と問題の詳細が含まれるテーブルがあります。

面白いことが起こっています-実際、何が間違っているのかを最終的に理解したとき、それはかなり明白でした...ログテーブルへの挿入ステートメントもロールバックされているため、これをSSMSから実行していない場合、ロールバックによってアクティビティの痕跡がすべて削除されるため、これが実行されたことさえ確認できません。

質問:
この単一の挿入ステートメントを除いて、トランザクション全体をロールバックすることは可能でしょうか? ストアド プロシージャの実行中にコンパイルしたエラー メッセージを保持したいと思います。

本当にありがとう!

〜エリ

更新 6/28
これは私が見ているもののコードサンプルです。これと @Alex および @gameiswar によって提示されたサンプルとの主な違いは、私の場合、try/catch ブロックがすべて単一のトランザクション内にネストされていることです。これの目的は、(複数のテーブルに対して) 複数のキャッチを取得することですが、最後の更新が失敗した場合でも、混乱全体がロールバックされるようにします。

SET XACT_ABORT ON;  
BEGIN TRANSACTION  
    DECLARE @message AS VARCHAR(MAX) = '';  

    -- TABLE 1
    BEGIN TRY
        UPDATE TABLE xx 
        SET yy = zz
    END TRY
    BEGIN CATCH
        SET @message = 'TABLE 1 '+ ERROR_MESSAGE();

        INSERT INTO LOGTABLE
        SELECT 
            GETDATE(),
            @message
        RETURN;
    END CATCH

    -- TABLE 2
    BEGIN TRY
        UPDATE TABLE sss 
        SET tt = xyz
    END TRY
    BEGIN CATCH
        SET @message = 'TABLE 2 '+ ERROR_MESSAGE();

        INSERT INTO LOGTABLE
        SELECT 
            GETDATE(),
            @message
        RETURN;
    END CATCH
COMMIT TRANSACTION
4

3 に答える 3

1

詳細はわかりませんが、私見の一般的なロジックは次のようになります。

--set XACT_ABORT ON --not include it
declare @result varchar(max) --collect details in case you need it
begin transaction
begin try
--your logic here
--if something wrong RAISERROR(...@result)
--everything OK
commit
end try
begin catch
--collect error_message() and other into @result
rollback
end catch
insert log(result) values (@result)
于 2016-06-27T21:16:59.847 に答える
1

わかりました... Alex と GameisWar による優れた提案と、T-SQL GOTO 制御フロー ステートメントの追加を組み合わせて、これを解決することができました。

基本的なアイデアは、エラー メッセージを変数に格納し、ロールバック後も存続するようにし、Catch に次の処理を行う FAILURE ラベルに送信させることでした。

  • トランザクションをロールバックする
  • 前述の変数のデータを使用して、ログ テーブルにレコードを挿入します。
  • ストアド プロシージャを終了する

また、2 つ目の GOTO ステートメントを使用して、実行が成功すると FAILURE セクションがスキップされ、トランザクションがコミットされるようにします。

以下は、テスト SQL のコード スニペットです。それは魔法のように機能し、私はすでにこれを実装し、実稼働環境で (正常に) テストしました。

私はすべての助けと意見に本当に感謝しています!

SET XACT_ABORT ON               
DECLARE @MESSAGE VARCHAR(MAX) = '';

BEGIN TRANSACTION 
    BEGIN TRY
        INSERT INTO TEST_TABLE VALUES ('TEST');     -- WORKS FINE
    END TRY 
    BEGIN CATCH     
        SET @MESSAGE = 'ERROR - SECTION 1: ' + ERROR_MESSAGE();
        GOTO FAILURE;
    END CATCH

    BEGIN TRY
        INSERT INTO TEST_TABLE VALUES ('TEST2');        --WORKS FINE
        INSERT INTO TEST_TABLE VALUES ('ANOTHER TEST'); -- ERRORS OUT, DATA WOULD BE TRUNCATED
    END TRY 
    BEGIN CATCH 
        SET @MESSAGE = 'ERROR - SECTION 2: ' + ERROR_MESSAGE();
        GOTO FAILURE;
    END CATCH

GOTO SUCCESS;

FAILURE:        
    ROLLBACK
    INSERT INTO LOGG SELECT @MESSAGE
    RETURN; 

SUCCESS:
COMMIT TRANSACTION
于 2016-07-06T21:33:43.410 に答える