0

初めてトランザクションを使用するので、ばかげた質問をしている可能性があります。

3 つのテーブルにデータを挿入したい:

Table1(p1,p2,p3)
Table2(q1,q2)
Table3(t3,fk1,fk2)

たとえば、何か問題が発生して にデータを挿入できない場合Table2、 からのデータはTable1失われず、変更さTable3れません (逆も同様です)。

これまでに 2 つのバージョンを試しましたが、どれも満足のいくものではありませんでした。

バージョン 1:

CREATE PROCEDURE InsertInto(@p1,@p2,@p3,@q1,@q2,@t3))
AS BEGIN

BEGIN TRAN
SET XACT_ABORT OFF

SAVE TRANSACTION point1
BEGIN TRY
    DECLARE @fk1 INT
    INSERT INTO Table1 VALUES (@p1,@p2,@p3)
    SELECT @fk1 = Table1.Id FROM Table1 WHERE Table1.p1 = @p1

    SAVE TRANSACTION point2
    BEGIN TRY
        DECLARE @fk2 INT
        INSERT INTO Table2 VALUES (@q1,@q2)
        SELECT @fk2 = Table2.Id FROM Table2 WHERE Table2.q1 = @q1

        SAVE TRANSACTION point3
        BEGIN TRY
            INSERT INTO Table3 VALUES (@t3, @fk1, @fk2)
            COMMIT TRAN
            END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION point3
            COMMIT TRAN
        END CATCH
        
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION point2
        COMMIT TRAN
    END CATCH

END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point1
    COMMIT TRAN
END CATCH
END

しかし、データを に挿入できない場合はTable1、可能なデータTable2が失われ、何も失いたくありません。というわけで、分けてみました。

バージョン 2:

CREATE PROCEDURE InsertInto(@p1,@p2,@p3,@q1,@q2,@t3)
AS
BEGIN

BEGIN TRAN
SET XACT_ABORT OFF

SAVE TRANSACTION point1
BEGIN TRY
    DECLARE @fk1 INT
    INSERT INTO Table1 VALUES (@p1,@p2,@p3)
    SELECT @fk1 = Table1.Id FROM Table1 WHERE Table1.p1 = @p1
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point1
    COMMIT TRAN
END CATCH

SAVE TRANSACTION point2
BEGIN TRY
    DECLARE @fk2 INT
    INSERT INTO Table2 VALUES (@q1,@q2)
    SELECT @fk2 = Table2.Id FROM Table2 WHERE Table2.q1 = @q1
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point2
    COMMIT TRAN
END CATCH

SAVE TRANSACTION point3
BEGIN TRY
    INSERT INTO Table3 VALUES (@t3,@fk1,@fk2)
    COMMIT TRAN
 END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point3
    COMMIT TRAN
 END CATCH
END

しかし、Table2 への挿入が失敗した場合は、次のようになります。

(1 行が影響を受けます)

(影響を受ける行は 0 行)
メッセージ 628、レベル 16、状態 0、手順 InsertInto、行 26 (2 番目の BEGIN CATCH)
アクティブなトランザクションがない場合、SAVE TRANSACTION を発行できません。

どうすればこれを正しく行うことができますか?

4

1 に答える 1

1

SAVE TRAN ではトランザクション数 > 0 が必要なため、前の CATCH ブロックでトランザクションをコミットしている必要があります。いくつかのオプションがあります:

1) SAVE TRAN ステートメントを次のように置き換えます (同じセーブポイント名を使用できますが、ロールバックは最後のセーブポイントまでしかロールバックしません)。

IF @@TRANCOUNT = 0
    BEGIN TRAN;
ELSE
    SAVE TRAN tran1;

2) CATCH ブロックで、COMMIT TRAN の後に BEGIN TRAN を追加します。

BEGIN CATCH
    ROLLBACK TRANSACTION point1
    COMMIT TRAN
    BEGIN TRAN
END CATCH

3) CATCH ブロック内のすべての COMMIT TRAN を削除し、最後に単一の COMMIT を実行します。

于 2015-05-11T22:21:14.467 に答える