SQL Server-エラー時にトランザクションがロールバックしますか?


192

次のようなSQL Server 2005でSQLを実行しているクライアントアプリがあります。

BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;

1つの長い文字列コマンドによって送信されます。

挿入の1つが失敗した場合、またはコマンドの一部が失敗した場合、SQL Serverはトランザクションをロールバックしますか?ロールバックしない場合は、2番目のコマンドを送信してロールバックする必要がありますか?

使用しているAPIと言語の詳細を指定できますが、SQL Serverはどの言語でも同じように応答するはずです。


回答:


204

set xact_abort onエラーが発生した場合にSQLが自動的にロールバックするように、トランザクションの前に置くことができます。


1
これはMS SQL 2K以降で機能しますか?これが最も簡単な解決策のようです。
ジョナサンペッパーズ

1
2000、2005、および2008のドキュメントに記載されているので、そうだと思います。2008年に使用しています

8
オフにする必要がありますか、それともセッションごとですか?
マルク・

5
@Marcのスコープはxact_abort接続レベルです。
キース

2
@AlexMcMillan DROP PROCEDUREステートメントは、データを操作するだけのINSERTとは異なり、データベース構造を変更します。したがって、トランザクションでラップすることはできません。私は単純化しすぎですが、基本的にそれはそうです。
eksortso 2017年

195

トランザクション全体がロールバックされるという点であなたは正しいです。それをロールバックするには、コマンドを発行する必要があります。

これTRY CATCHを次のようにブロックでラップすることができます

BEGIN TRY
    BEGIN TRANSACTION

        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);

    COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN --RollBack in case of Error

    -- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH

2
私はDyingCactusのソリューションの方が好きです。彼は変更する1行のコードです。もしあなたの場合、何らかの理由でより良い(またはより信頼できる)場合は私に知らせてください。
ジョナサンペッパーズ

13
トライキャッチを使用すると、エラーをキャプチャして(場合によっては修正して)、必要に応じてカスタムエラーメッセージを生成することができます。
Raj More

10
「キャプチャして修正」よりも「キャプチャしてログ」の方が頻繁だと思います。
キルブレーカー、2012

24
RAISERRORの構文は、少なくともSQL Server 2008R2以降では正しくありません。正しい構文については、msdn.microsoft.com / en-us / library / ms178592.aspxを参照してください
エリックJ.

2
@BornToCodeトランザクションが存在することを確認するには...特定の条件(内try)でトランザクションをロールバックしたが、その後コードが失敗したとします。これ以上トランザクションはありませんが、まだにアクセスしていcatchます。
ガブリエルGM

42

ここで、MSSQL Server 2016で動作するエラーメッセージを取得するコード:

BEGIN TRY
    BEGIN TRANSACTION 
        -- Do your stuff that might fail here
    COMMIT
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN

        DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
        DECLARE @ErrorSeverity INT = ERROR_SEVERITY()
        DECLARE @ErrorState INT = ERROR_STATE()

    -- Use RAISERROR inside the CATCH block to return error  
    -- information about the original error that caused  
    -- execution to jump to the CATCH block.  
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH

1
DECLARE @Var TYPE; SET @Var = ERROR;SQL Server 2005でエラーを発生させるために使用する必要がありました。それ以外の場合、エラーを発生させるための上記のコードは、古いDBでも機能します。ローカル変数にデフォルト値を割り当てようとすると、問題が発生していました。
jtlindsey

単純なTHROWを使用できます。RAISERRORおよびERROR_ *宣言の代わりに。
rodzmkii

21

MDSNの記事、トランザクションの制御(データベースエンジン)から

ランタイムステートメントエラー(制約違反など)がバッチで発生した場合、データベースエンジンのデフォルトの動作では、エラーを生成したステートメントのみがロールバックされます。この動作は、SET XACT_ABORTステートメントを使用して変更できます。SET XACT_ABORT ONが実行された後、ランタイムステートメントエラーが発生すると、現在のトランザクションが自動的にロールバックされます。構文エラーなどのコンパイルエラーは、SET XACT_ABORTの影響を受けません。詳細については、「SET XACT_ABORT(Transact-SQL)」を参照してください。

あなたの場合、いずれかの挿入が失敗すると、トランザクション全体がロールバックされます。


3
構文エラーを処理するために何が必要ですか?またはコンパイルエラー?それらのいずれかが発生した場合、トランザクション全体をロールバックする必要があります
MonsterMMORPG

SSDTプロジェクトの目的は、コンパイル/構文エラーをキャッチすることです。:-)
Joe the Coder

10

挿入の1つが失敗した場合、またはコマンドの一部が失敗した場合、SQLサーバーはトランザクションをロールバックしますか?

いいえ、違います。

ロールバックしない場合は、2番目のコマンドを送信してロールバックする必要がありますか?

もちろん、ROLLBACKではなく発行する必要がありCOMMITます。

トランザクションをコミットするかロールバックするかを決定する場合COMMITは、ステートメントから文を削除し、挿入の結果をチェックしてから、チェックの結果に応じて、COMMITまたはROLLBACKその結果に応じて発行する必要があります。


エラーが発生した場合は、「主キーの競合」と言って、ロールバックするために2番目の呼び出しを送信する必要がありますか?それは理にかなっていると思います。非常に長いSQLステートメントの実行中に接続が切断されるなど、ネットワーク関連のエラーが発生した場合はどうなりますか?
ジョナサンペッパーズ

2
接続がタイムアウトすると、基盤となるネットワークプロトコル(Named PipesまたはなどTCP)が接続を切断します。接続が切断されると、SQL Server現在実行中のすべてのコマンドを停止し、トランザクションをロールバックします。
Quassnoi、2009年

1
DyingCactusの解決策は私の問題を解決するように見えます。助けてくれてありがとう。
ジョナサンペッパーズ

あなたが上で中止する必要がある場合は任意のエラー、[はい、これが最良の選択肢です。
Quassnoi、2009年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.