2011-09-20 216 views
26

The current transaction cannot be committed and cannot support operations that write to the log fileと同様の問題が発生していますが、フォローアップの質問があります。SQLトランザクションエラー:現在のトランザクションをコミットできず、ログファイルに書き込む操作をサポートできません

答え私は2番目...

私のコードに戻って来るUsing TRY...CATCH in Transact-SQLは、(もちろん、継承された)が参照するには、簡略化した形を持っています

SET NOCOUNT ON 
SET XACT_ABORT ON 

CREATE TABLE #tmp 

SET @transaction = 'insert_backtest_results' 
BEGIN TRANSACTION @transaction 

BEGIN TRY 

    --do some bulk insert stuff into #tmp 

END TRY 

BEGIN CATCH 
    ROLLBACK TRANSACTION @transaction 
    SET @errorMessage = 'bulk insert error importing results for backtest ' 
     + CAST(@backtest_id as VARCHAR) + 
     '; check backtestfiles$ directory for error files ' + 
     ' error_number: ' + CAST(ERROR_NUMBER() AS VARCHAR) + 
     ' error_message: ' + CAST(ERROR_MESSAGE() AS VARCHAR(200)) + 
     ' error_severity: ' + CAST(ERROR_SEVERITY() AS VARCHAR) + 
     ' error_state ' + CAST(ERROR_STATE() AS VARCHAR) + 
     ' error_line: ' + CAST(ERROR_LINE() AS VARCHAR) 
    RAISERROR(@errorMessage, 16, 1) 
    RETURN -666 
END CATCH 

BEGIN TRY 

    EXEC usp_other_stuff_1 @whatever 

    EXEC usp_other_stuff_2 @whatever 

    -- a LOT of "normal" logic here... inserts, updates, etc... 

END TRY 

BEGIN CATCH 

    ROLLBACK TRANSACTION @transaction 
    SET @errorMessage = 'error importing results for backtest ' 
     + CAST(@backtest_id as VARCHAR) + 
     ' error_number: ' + CAST(ERROR_NUMBER() AS VARCHAR) + 
     ' error_message: ' + CAST(ERROR_MESSAGE() AS VARCHAR(200)) + 
     ' error_severity: ' + CAST(ERROR_SEVERITY() AS VARCHAR) + 
     ' error_state ' + CAST(ERROR_STATE() AS VARCHAR) + 
     ' error_line: ' + CAST(ERROR_LINE() AS VARCHAR) 
    RAISERROR(@errorMessage, 16, 1) 
    RETURN -777 

END CATCH 

RETURN 0 

私は私だと思います残念ながらそのエラーを再現することは不可能に近いことを証明しています。だから私はここで尋ねることが、問題と解決策についての私の理解を明確にするのに役立つことを願っています。

このストアドプロシージャで、断続的に、この1のようなエラーをスロー:だから、明らかにエラーが私はUsing TRY...CATCH in Transact-SQLで読んだことに基づいて、第二のcatchブロック

から来ている

error importing results for backtest 9649 error_number: 3930 error_message: The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction. error_severity: 16 error_state 1 error_line: 217

、I例外がスローされたときに、XACT_ABORTを使用するとトランザクションが「終了し、ロールバックされる」というメッセージが表示され、BEGIN CATCHの最初の行が盲目的に再びロールバックしようとしていることが考えられます。

元の開発者がXACT_ABORTを有効に理由を私は知らないので、私は(それを削除するよりも)よりよい解決策を考えているが、トランザクション(<>0)がある場合にのみロールバックするXACT_STATE()を使用することです。それは合理的に聞こえるか?何か不足していますか?

さらに、エラーメッセージに記録すると、次のような疑問が生じます。設定に問題がありますか?このシナリオでのRAISEERROR()の使用は問題に寄与していますか?エラーメッセージに示されているように、ロギングが不可能な場合に、ログに記録されますか?

答えて

27

XACT_ABORTの設定とは関係なく、常にXACT_STATE()を確認する必要があります。私はException handling and nested transactionsでTRY/CATCHコンテキストでトランザクションを処理する必要があるストアドプロシージャのためのテンプレートの例があります。

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 
+0

あなたのテンプレートはtryブロック内のトランザクションを想定しています。 1トランザクション内に複数のtryブロックがあります。 –

+0

@Adam:これは、 'XACT_STATE'とCATCHブロック内のトランザクションをどのように扱うかについてです。この非常にテンプレートを使用して、1つのトランザクションで複数のtryブロックを持つことができます。この考え方は、トランザクションとブロックをどのようにやりとりするかを理解することです。また、バッチの処理に非常に役立つネストされたトランザクションとセーブポイントの処理も得られます。これはバッチの残りの部分を再開する機能エントリが失敗しました。 –

+0

私は先に進んで、 'XACT_STATE()<> 0'でロールバック文をラップしましたが、時間があればそれが解決するかどうかがわかります。私は先に進み、あなたの答えを今受け入れます。 –

12

上記の議論では、いくつかの誤解があります。

まず、トランザクションの状態に関係なく、常にトランザクションをロールバックすることができます。したがって、ロールバックの前ではなく、COMMITの前にXACT_STATEをチェックするだけで済みます。

コード内のエラーまで、TRY内にトランザクションを入れたいと思うでしょう。次に、あなたのCATCHでは、あなたが最初にすべきことは以下の通りです:

IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION @transaction 

次に、上記の文の後に、あなたは、電子メールまたは何が必要であるを送信することができます。 (FYI:ロールバックの前にメールを送信すると、「ログファイルに書き込めません」というエラーが表示されます)

この問題は昨年からのものでしたので、今すぐ:-) Remusは正しい方向にあなたを指しています。

経験則として、TRYはエラーが発生したときにすぐにCATCHにジャンプします。次に、CATCHにいるときに、XACT_STATEを使用してコミットできるかどうかを判断できます。しかし、あなたがいつもキャッチでROLLBACKをしたいのであれば、その状態を一切チェックする必要はありません。

関連する問題