次のような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つの長い文字列コマンドによって送信されます。
挿入のいずれかが失敗した場合、またはコマンドの一部が失敗した場合、SQL Serverはトランザクションをロールバックしますか?ロールバックしない場合、ロールバックするために2番目のコマンドを送信する必要がありますか?
使用しているAPIと言語の詳細を指定できますが、SQL Serverはどの言語でも同じように応答するはずです。
トランザクションの前にset xact_abort on
を置くと、エラーが発生した場合にSQLが自動的にロールバックされるようにできます。
トランザクション全体がロールバックされるという点で正しいです。コマンドを発行してロールバックする必要があります。
次のように、これを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
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, -- Message text.
@ErrorSeverity, -- Severity.
@ErrorState -- State.
);
END CATCH
MDSNの記事、 Controlling Transactions(Database Engine) から。
バッチで実行時ステートメントエラー(制約違反など)が発生した場合、データベースエンジンのデフォルトの動作では、エラーを生成したステートメントのみがロールバックされます。この動作は、SET XACT_ABORTステートメントを使用して変更できます。 SET XACT_ABORT ONの実行後、実行時ステートメントエラーが発生すると、現在のトランザクションの自動ロールバックが発生します。構文エラーなどのコンパイルエラーは、SET XACT_ABORTの影響を受けません。詳細については、「SET XACT_ABORT(Transact-SQL)」を参照してください。
あなたの場合、挿入のいずれかが失敗すると、完全なトランザクションがロールバックされます。
挿入の1つが失敗した場合、またはコマンドの一部が失敗した場合、SQLサーバーはトランザクションをロールバックしますか?
いいえ、違います。
ロールバックしない場合、ロールバックするために2番目のコマンドを送信する必要がありますか?
もちろん、ROLLBACK
の代わりにCOMMIT
を発行する必要があります。
トランザクションをコミットするかロールバックするかを決定する場合は、ステートメントからCOMMIT
文を削除し、挿入の結果を確認してから、チェックの結果に応じてCOMMIT
またはROLLBACK
を発行する必要があります。