2026年2月6日金曜日

SQL Server トランザクションエラー時のロールバック処理設計|TRY...CATCHで安全に戻す方法

エラー時にデータ不整合を防ぐ!SQL Serverのロールバック処理を安全に設計する方法

SQL Serverで複数の更新処理をまとめて実行する場合、 途中でエラーが発生すると一部だけが更新されてしまうリスクがあります。 これを防ぐために使うのがトランザクション制御ロールバック処理です。
この記事では、TRY...CATCH構文を利用した安全なロールバック設計を 実務向けにわかりやすく解説します。

目次

トランザクションとロールバックの基本

トランザクションとは?

トランザクションは、複数のSQL処理をひとまとまりとして扱う仕組みです。 すべての処理が成功すればコミット(確定)、どれかが失敗すればロールバック(取消)します。

基本構文


BEGIN TRANSACTION;

UPDATE Customers SET Balance = Balance - 1000 WHERE CustomerID = 1;
UPDATE Customers SET Balance = Balance + 1000 WHERE CustomerID = 2;

COMMIT TRANSACTION;

上記の2つの更新が両方成功した場合のみ確定されます。

ロールバック処理

途中でエラーが発生した場合、次のように戻せます。


ROLLBACK TRANSACTION;

これにより、実行前の状態に戻ります。

エラー時に部分更新を防ぐ仕組み

なぜTRY...CATCHが必要なのか

SQL Serverでは、単純にROLLBACKを書くだけではエラーを自動検知できません。 そこでTRY...CATCH構文を使い、エラー発生時に確実にROLLBACKする仕組みを構築します。

誤った例


BEGIN TRANSACTION;
UPDATE Products SET Price = Price / 0;  -- エラー発生
ROLLBACK TRANSACTION;  -- 実行されない

このように、エラーで処理が中断するとROLLBACKまで到達しません。

TRY...CATCH構文での基本設計

正しいロールバック構成例


BEGIN TRY
    BEGIN TRANSACTION;

    UPDATE Customers SET Balance = Balance - 500 WHERE CustomerID = 1;
    UPDATE Customers SET Balance = Balance + 500 WHERE CustomerID = 2;

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;

    DECLARE @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE();
    PRINT 'ロールバック実行: ' + @ErrMsg;
END CATCH;

このようにすることで、例外が発生しても必ずROLLBACKが実行されます。

ネスト構造での注意点と@@TRANCOUNTの活用

ネストトランザクションの落とし穴

ストアドプロシージャ内でトランザクションを入れ子にする場合、 複数回のBEGIN TRANSACTIONでも1つのトランザクションとして扱われます。

@@TRANCOUNTの確認


PRINT '現在のトランザクション数: ' + CAST(@@TRANCOUNT AS NVARCHAR(10));

@@TRANCOUNTが1以上であればトランザクション中です。 CATCH内ではこれを確認してからROLLBACKを行うのが安全です。

RAISERRORとの組み合わせによるログ通知

ログ出力付きのCATCH構文


BEGIN TRY
    BEGIN TRANSACTION;
    INSERT INTO Sales VALUES (1, 1000, GETDATE());
    INSERT INTO Sales VALUES (NULL, 2000, GETDATE());  -- エラー
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;

    DECLARE @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE();
    RAISERROR('エラー発生: %s', 16, 1, @ErrMsg) WITH LOG;
END CATCH;

WITH LOGを指定すれば、SQL Serverエラーログにも記録されます。

実務で使えるテンプレート構文

汎用トランザクション制御テンプレート


CREATE PROCEDURE usp_UpdateOrder
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
        BEGIN TRANSACTION;

        -- 処理開始
        UPDATE Orders SET Status = 'Completed' WHERE OrderID = 1001;

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;

        DECLARE 
            @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE(),
            @ErrProc NVARCHAR(128) = ERROR_PROCEDURE();

        RAISERROR('処理失敗(%s): %s', 16, 1, @ErrProc, @ErrMsg) WITH LOG;
    END CATCH;
END;

このようにプロシージャ単位で統一的に組み込むことで、 エラーログ・トランザクション整合性を両立できます。

まとめと次のステップ

学んだ内容の整理

  • トランザクションは複数処理をひとまとめにし、整合性を確保する。
  • TRY...CATCHを使うことで、エラー発生時も安全にROLLBACK可能。
  • @@TRANCOUNTでトランザクションの状態を確認してから処理。
  • RAISERRORと組み合わせてログ通知・監査を実現。

参考リンク

SQL Server 解説用イメージ

0 件のコメント:

コメントを投稿