web-dev-qa-db-ja.com

ストアドプロシージャでトランザクションをロールバックする方法は?

SQL Server Books Onlineを見ると、Microsoftはストアドプロシージャでネストされたトランザクションを処理する(不正な) メソッドを持っているようです

入れ子のトランザクション

明示的なトランザクションはネストできます。これは主に、すでにトランザクション内にあるプロセスから、またはアクティブなトランザクションがないプロセスから呼び出すことができるストアドプロシージャのトランザクションをサポートすることを目的としています。

この例では、独自のトランザクションを開始するストアドプロシージャを示します( "プロシージャは、それを実行するプロセスのトランザクションモードに関係なく、トランザクションを強制します。")

CREATE PROCEDURE TransProc @PriKey INT, @CharCol CHAR(3) AS
   BEGIN TRANSACTION InProc
      ...
   COMMIT TRANSACTION InProc;

このプロシージャは、トランザクションを実行せずに呼び出すことができます。

EXECUTE TransProc 3,'bbb';

または、with明示的なトランザクション:

BEGIN TRANSACTION OutOfProc;

EXEC TransProc 1, 'aaa';

COMMIT TRANSACTION OutOfProc

彼らが対処していないのは、格納されたプロシージャが次の場合に何が起こるかです。

  • エラーで失敗しますが、トランザクションは実行されたままです
  • エラーで失敗するが、トランザクションを実行したままにしない
  • エラーが発生しましたが、トランザクションを開いたまま実行を継続します
  • エラーが発生しましたが、トランザクションをロールバックして実行を継続します

ありません:

  • SET XACT_ABORT ON
  • @@ TRANCOUNT

標準的な例のどこでも。

もっとよくわからなければ、次のように考えていました。

次の例は、ネストされたトランザクションの使用目的を示しています。

実際に読むべき

次の例は、ネストされたトランザクションを使用しない方法を示しています。

誰かがこのBOLの例の表または裏を作成できない限り、

10
Ian Boyd

トランザクションでtry catchブロックを使用する必要があります。したがって、catchブロックでエラーが発生した場合は、トランザクションをロールバックできます。

これについては、以下のSQLサーバーコードを参照してください。

BEGIN TRANSACTION;

BEGIN TRY
    -- Some code
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH

    ROLLBACK TRANSACTION;
END CATCH;
32
Mayur Desai
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