SET XACT_ABORT ONストアドプロシージャで使用する利点は何ですか?
SET XACT_ABORT ONストアドプロシージャで使用する利点は何ですか?
回答:
SET XACT_ABORT ON実行時エラーが発生すると、トランザクション全体をロールバックし、バッチを中止するようにSQL Serverに指示します。SQL Server自体ではなく、クライアントアプリケーションで発生するコマンドタイムアウトなどの場合に対応します(既定のXACT_ABORT OFF設定ではカバーされません)。
クエリタイムアウトはトランザクションを開いたままにするので、SET XACT_ABORT ON開いているトランザクションとの接続でアプリケーションが作業を実行する結果は悲惨なので、明示的なトランザクションがあるすべてのストアドプロシージャで推奨されます(特別な理由がない限り)。
Dan Guzmanのブログには本当に素晴らしい概要があります。
BEGIN TRY-がBEGIN CATCHあり、SQL ROLLBACKのBEGIN CATCHブロックがある場合、XACT_ABORTは引き続き必要ですか?
BEGIN TRY- BEGIN CATCHあなたは1を期待していない開いているトランザクションであなたを残して、あまりにも、クライアントアプリケーション上で発生するタイムアウトのようなものをキャッチし、いくつかのSQLエラーがキャッチできていることはありません。
私の意見では、SET XACT_ABORT ONは、SQL 2k5にBEGIN TRY / BEGIN CATCHを追加することで廃止されました。Transact-SQLの例外ブロックの前は、エラーを処理するのが本当に難しく、不均衡なプロシージャが一般的でした(出口と入口で異なる@@ TRANCOUNTがあったプロシージャ)。
Transact-SQLの追加により、トランザクションのバランスを適切に保つことが保証されている正しいプロシージャを書くのがはるかに簡単になります。たとえば、例外処理とネストされたトランザクションにこのテンプレートを使用します。
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
end catch
end
go
回復可能なエラーが発生した場合に、自分の作業だけをロールバックするアトミックプロシージャを作成できます。
Transact-SQLプロシージャが直面する主な問題の1つはデータの純度です。受信したパラメーターまたはテーブル内のデータがまったく間違っている場合があり、その結果、重複キーエラー、参照制約エラー、チェック制約エラーなどが発生します。結局のところ、それがまさにこれらの制約の役割です。これらのデータ純度エラーが不可能であり、すべてがビジネスロジックによってキャッチされる場合、制約はすべて廃止されます(劇的な誇張が効果のために追加されます)。XACT_ABORTがONの場合、これらのすべてのエラーにより、例外を適切に処理する例外ブロックをコーディングするのではなく、トランザクション全体が失われます。典型的な例は、INSERTを実行しようとし、PK違反でUPDATEに戻ることです。
MSDNの引用:
SET XACT_ABORTがONの場合、Transact-SQLステートメントで実行時エラーが発生すると、トランザクション全体が終了し、ロールバックされます。SET XACT_ABORTがOFFの場合、エラーが発生したTransact-SQLステートメントのみがロールバックされ、トランザクションは処理を続行します。
実際には、これは一部のステートメントが失敗し、トランザクションが「部分的に完了」したままになる可能性があることを意味し、呼び出し側にはこの失敗の兆候がない場合があります。
簡単な例:
INSERT INTO t1 VALUES (1/0)
INSERT INTO t2 VALUES (1/1)
SELECT 'Everything is fine'
このコードは、XACT_ABORT OFFで「正常に」実行され、XACT_ABORT ONでエラーで終了します(「INSERT INTO t2」は実行されず、クライアントアプリケーションは例外を発生させます)。
より柔軟なアプローチとして、各ステートメントの後に@@ ERRORをチェックするか(古い学校)、またはTRY ... CATCHブロックを使用できます(MSSQL2005 +)。個人的には、高度なエラー処理の理由がない場合は常にXACT_ABORTをONに設定することを好みます。
クライアントのタイムアウトとそれらを処理するためのXACT_ABORTの使用に関して、私の意見では、SqlClientなどのクライアントAPIでタイムアウトを設定する理由は少なくとも1つあります。これは、SQLサーバーコードで発生するデッドロックからクライアントアプリケーションコードを保護するためです。この場合、クライアントコードに障害はありませんが、サーバー上でコマンドが完了するのを待って、クライアントコードが永久にブロックされるのを防ぐ必要があります。したがって、逆に、クライアントコードを保護するためにクライアントタイムアウトが存在する必要がある場合、クライアントが待機するよりもサーバーコードの実行に時間がかかる場合に備えて、XACT_ABORT ONはクライアントアボートからサーバーコードを保護する必要があります。