SAVE TRANSACTION (Transact-SQL)

トランザクション内でセーブポイントを設定します。

トピック リンク アイコンTransact-SQL 構文表記規則

構文

SAVE { TRAN | TRANSACTION } { savepoint_name | @savepoint_variable }
[ ; ]

引数

  • savepoint_name
    セーブポイントに割り当てる名前を指定します。セーブポイント名は識別子の規則に従う必要があります。文字数は半角 32 文字に制限されます。

  • @savepoint_variable
    有効なセーブポイント名を含むユーザー定義の変数名を指定します。この変数は、char 型、varchar 型、nchar 型、または nvarchar 型で宣言する必要があります。この変数には 32 文字を超える文字列も渡されますが、使用されるのは最初の 32 文字だけです。

説明

ユーザーは、トランザクション内にセーブポイントというマーカーを設定できます。セーブポイントでは、トランザクションの一部が条件付きで取り消された場合に、トランザクションが戻ることのできる位置を定義します。トランザクションがセーブポイントまでロールバックされた場合は、必要であれば追加の Transact-SQL ステートメントと、COMMIT TRANSACTION ステートメントを使用して、トランザクションを最後まで実行します。最後まで実行しない場合は、開始位置までロールバックしてトランザクション全体を取り消す必要があります。トランザクション全体を取り消す場合は、ROLLBACK TRANSACTION transaction_name を使用します。この場合、そのトランザクションのすべてのステートメントまたはプロシージャが取り消されます。

1 つのトランザクションでは同じセーブポイント名を重複して指定できますが、ROLLBACK TRANSACTION ステートメントでそのセーブポイント名を指定した場合は、そのセーブポイント名を使用している最新の SAVE TRANSACTION のみにロールバックできます。

BEGIN DISTRIBUTED TRANSACTION で明示的に起動された分散トランザクション、またはローカル トランザクションから拡大された分散トランザクションでは、SAVE TRANSACTION はサポートされません。

重要な注意事項重要

トランザクションが開始されると、そのトランザクションで使用されるリソースはトランザクションが完了するまで保持 (ロック) されます。トランザクションの一部がセーブポイントまでロールバックされても、リソースはトランザクションが完了するかトランザクション全体がロールバックされるまで引き続き保持されます。

権限

public ロールのメンバーシップが必要です。

次の例では、ストアド プロシージャの実行前にアクティブなトランザクションが開始された場合に、トランザクション セーブポイントを使用して、ストアド プロシージャによる変更だけをロールバックする方法を示します。

USE AdventureWorks2008R2;
GO
IF EXISTS (SELECT name FROM sys.objects
           WHERE name = N'SaveTranExample')
    DROP PROCEDURE SaveTranExample;
GO
CREATE PROCEDURE SaveTranExample
    @InputCandidateID INT
AS
    -- Detect whether the procedure was called
    -- from an active transaction and save
    -- that for later use.
    -- In the procedure, @TranCounter = 0
    -- means there was no active transaction
    -- and the procedure started one.
    -- @TranCounter > 0 means an active
    -- transaction was started before the 
    -- procedure was called.
    DECLARE @TranCounter INT;
    SET @TranCounter = @@TRANCOUNT;
    IF @TranCounter > 0
        -- Procedure called when there is
        -- an active transaction.
        -- Create a savepoint to be able
        -- to roll back only the work done
        -- in the procedure if there is an
        -- error.
        SAVE TRANSACTION ProcedureSave;
    ELSE
        -- Procedure must start its own
        -- transaction.
        BEGIN TRANSACTION;
    -- Modify database.
    BEGIN TRY
        DELETE HumanResources.JobCandidate
            WHERE JobCandidateID = @InputCandidateID;
        -- Get here if no errors; must commit
        -- any transaction started in the
        -- procedure, but not commit a transaction
        -- started before the transaction was called.
        IF @TranCounter = 0
            -- @TranCounter = 0 means no transaction was
            -- started before the procedure was called.
            -- The procedure must commit the transaction
            -- it started.
            COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        -- An error occurred; must determine
        -- which type of rollback will roll
        -- back only the work done in the
        -- procedure.
        IF @TranCounter = 0
            -- Transaction started in procedure.
            -- Roll back complete transaction.
            ROLLBACK TRANSACTION;
        ELSE
            -- Transaction started before procedure
            -- called, do not roll back modifications
            -- made before the procedure was called.
            IF XACT_STATE() <> -1
                -- If the transaction is still valid, just
                -- roll back to the savepoint set at the
                -- start of the stored procedure.
                ROLLBACK TRANSACTION ProcedureSave;
                -- If the transaction is uncommitable, a
                -- rollback to the savepoint is not allowed
                -- because the savepoint rollback writes to
                -- the log. Just return to the caller, which
                -- should roll back the outer transaction.

        -- After the appropriate rollback, echo error
        -- information to the caller.
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = ERROR_MESSAGE();
        SELECT @ErrorSeverity = ERROR_SEVERITY();
        SELECT @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage, -- Message text.
                   @ErrorSeverity, -- Severity.
                   @ErrorState -- State.
                   );
    END CATCH
GO