2017-10-24 11 views
0

私のストアドプロシージャの1つに問題があります。ロールバック後にN-deepログを持続する

私はrecursiveChildren自分自身を呼び出すトランザクションを呼び出して、mainプロシージャを実行します。このような

何か:

EXEC main 
{ 
    EXEC log 'START' 

    BEGIN TRANSACTION 
     BEGIN TRY 
      EXEC recursiveChildren 
      { 
       IF ... 
        EXEC recursiveChildren 
        { 
         IF ... 
          EXEC recursiveChildren 
          { 
           ... 
          } 
         END IF 
         EXEC log 'step X' 
        } 
       END IF 
       EXEC log 'step X' 
      } 

      IF ... 
       COMMIT; 
      ELSE 
       THROW error; 
     END TRY 
     BEGIN CATCH 
      ROLLBACK; 
      EXEC log 'ROLLBACK' 
     END CATCH 
    END TRANSACTION 

    EXEC log 'STOP' 
} 

あなたが見ることができるように、私は私がやっているものに追跡するためにログプロシージャを呼び出すが、私は私のTHROW errorを使用する必要がある場合、私はすべての情報を失いますよ何が起こったかについて

ログとロールバックについてはTSQL logging inside transactionと書かれていますが、table variableはプロシージャのパラメータとして使用されたときにはREADONLYであるため、再帰には適していません。

ロールバックするたびにログを保存するにはどうすればよいですか?

+0

:誰かが同じ問題に直面している場合はここ

はコードです。唯一の例外は、ログ変数を保持するためにテーブル変数を使用したが、独自の課題である再帰を使用しているためです。このためには、テーブル値のパラメータを何度も渡す必要があります。あなたがしなければならないことは、各反復で同じデータ型のローカルインスタンスを作成し、渡されたパラメータで満たすことです。次に、再帰時に新しいローカルバージョンを渡します。維持するのは醜い悪夢です。 –

+0

@SeanLangeはい私はトランザクション処理の仕組みにかなり精通していますが、ロールバックはロジックの一部であり、「なぜロールバックするのか」も必須です。だから私は選択肢がありません。 readonlyにあるように 'table variable'を再帰的に使用しても、私は子供のログを親に戻すことができません(技術的には、プロシージャからデータを抽出するために使用することはできません)。 – Blag

+0

外側のスコープのエラーハンドラでロールバックされた質問のように構造化されている場合は、一時テーブルを使用して、ロールバックを実行する前に内容をテーブル変数にコピーすることができます。 –

答えて

0

私の場合の解決策は、私の場合、更新前にログをvarテーブルに移動することです。あなたがトランザクション内でこのような挿入を持っていて、それが戻ってすべてをロールそのトランザクションをロールバックする場合

CREATE PROCEDURE dbo.[main] 
AS 
BEGIN 
    WHILE EXISTS(SELECT 1 FROM #tmp) 
    BEGIN 

     SET @last_id_log = (SELECT MAX([id]) FROM Logs); 

     BEGIN TRANSACTION; 
     BEGIN TRY 

      SET @last_nb_error = @nb_error; 

      EXEC dbo.[child] @nb_error output; -- recursive call of child 

      IF(@nb_error - @last_nb_error = 0) 
       COMMIT TRANSACTION; 
      ELSE 
       THROW 66666, 'Error while child, ROLLBACK', 1; 

     END TRY 
     BEGIN CATCH 

      DECLARE @LogTable TABLE 
       ([id] [int] 
       ,[date] [datetime] 
       ,[userName] [varchar](100) 
       ,[error] [varchar](1000) 
       ); 

      INSERT INTO @LogTable 
      SELECT * 
      FROM Logs 
      WHERE [Id] > @last_id_log 
      ; 

      ROLLBACK TRANSACTION; 

      INSERT INTO Logs 
      SELECT * 
      FROM @LogTable 
      ; 

      DELETE FROM @LogTable; 
     END CATCH 

    END 
END 
関連する問題