SQL ServerジョブでのトランザクションとTry-Catch


9

SQL Serverジョブの各ステップにはDML操作があります。更新を確保するために/挿入は、何かがうまくいかない場合にはロールバックされます、私はのデータ修正包まれている各ステップをTRY CATCHしてTRANSACTIONブロック:

BEGIN TRY
    BEGIN TRANSACTION

        [[INSERT/update statements]] ...

    IF @@TRANCOUNT > 0
    BEGIN
        COMMIT TRANSACTION
        PRINT 'Successful.'
    END

END TRY

BEGIN CATCH
    SELECT
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage

    IF @@TRANCOUNT > 0
    BEGIN
        ROLLBACK TRANSACTION
        PRINT 'Unsuccessful.'
    END
END CATCH

エラーが発生した場合、データ操作が確実にロールバックされますか?または他の考慮事項を考慮する必要がありますか?

(構成などを使用して)それを行うより良い方法はありますか?

ありがとうございました。

回答:


7

むしろ、例外処理とネストされたトランザクションのようなパターンをお勧めします。

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch   
end

このパターンXACT_STATE()は、catchブロックのをチェックして、コミットできないトランザクションから保護します。

コミットできないトランザクションとXACT_STATE
TRYブロックで生成されたエラーによって現在のトランザクションの状態が無効になる場合、そのトランザクションはコミットできないトランザクションとして分類されます。通常、TRYブロックの外部でトランザクションを終了するエラーにより、TRYブロックの内部でエラーが発生した場合、トランザクションはコミットできない状態になります。コミットできないトランザクションは、読み取り操作またはROLLBACK TRANSACTIONのみを実行できます。トランザクションは、書き込み操作またはCOMMIT TRANSACTIONを生成するTransact-SQLステートメントを実行できません。トランザクションがコミットできないトランザクションとして分類されている場合、XACT_STATE関数は値-1を返します。バッチが完了すると、データベースエンジンはアクティブなコミットできないトランザクションをすべてロールバックします。トランザクションがコミットできない状態になったときにエラーメッセージが送信されなかった場合、バッチが完了すると、エラーメッセージがクライアントアプリケーションに送信されます。これは、コミットできないトランザクションが検出され、ロールバックされたことを示しています。

コードは@@TRANCOUNT、0にできない場所でチェックしています。成功を通知するために、情報を提供するPRINTメッセージとSELECT結果セットが混在して使用されています。回復可能なエラーは処理しません。理想的には、例外はクライアント、この場合はエージェントジョブに伝播する必要があります(つまり、キャッチは再発生する必要があります)。


あなたの役に立つ答えと素晴らしいウェブサイトをありがとう!しかし、私はまだこのパターンを(ストアドプロシージャではなく)単純なDMLステートメントで使用できるかどうか疑問に思っていますか?また、以下のようにトランザクションを保存する必要がありますか?(使用するストアプロシージャがありません):トランザクションusp_my_procedure_nameを保存します。
スカイ

2

あなたが持っているものは私にはよさそうだ。もちろん、トランザクションをロールバックした後、ログに書き出すなど、情報を使用して何かを行うことをお勧めします。


1
返信ありがとうございます。ログに書き込む方法のヒントを教えていただけませんか。
スカイ

3
エラーまたはデータをログテーブルに書き込む場合は、ロールバックを実行する前に、必要なデータをテーブル変数にコピーします(テーブル変数を使用することが重要です。一時テーブルがロールバックされます)。ロールバックし、テーブル変数からログテーブルにデータを挿入します。
HLGEM 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.