TRY
これは、 /でラップされていない実行時構文エラーが、に設定されてCATCH
いても、アクティブなトランザクションを中止しないために発生します。何が中止され、何が中止されないか、およびどのような状況下で行われるかについての正確な規則は、まったく単純でも明白でもありません。Erland Sommarskog は、一般的なエラー処理と、特に異常終了するものとしないものの規則について優れた記事を書いています。XACT_ABORT
ON
ここですべてを再現することはしませんが、問題を要点に要約すると次のようになります。
SET XACT_ABORT ON -- or OFF, it makes no difference
BEGIN TRANSACTION
EXEC ('SELECT') -- Incorrect syntax near 'SELECT'
PRINT @@TRANCOUNT -- Prints 1, transaction is still going
COMMIT
PRINT @@TRANCOUNT -- Prints 0, transaction succeeded
にもかかわらずXACT_ABORT ON
、実行が停止しないだけでなく、トランザクションが中止されることさえありません。ルールの追加TRY
/変更:CATCH
SET XACT_ABORT ON
BEGIN TRANSACTION
BEGIN TRY
EXEC ('SELECT') -- Incorrect syntax near 'SELECT'
PRINT 'After bad statement.' -- Does not print
COMMIT
END TRY
BEGIN CATCH
PRINT @@TRANCOUNT -- Prints 1, transaction is still going, but it's doomed
END CATCH
-- Error here:
-- 'Uncommittable transaction is detected at the end of the batch.
-- The transaction is rolled back.'
これで、トランザクションは運命づけられました。自分でロールバックしないと、SQL Server が代わりに (エラーで) ロールバックします。XACT_ABORT
これをオフにすると、また別の結果が得られるため、この運命は完全に の好意によるものです。
SET XACT_ABORT OFF
BEGIN TRANSACTION
BEGIN TRY
EXEC ('SELECT') -- Incorrect syntax near 'SELECT'
PRINT 'After bad statement.' -- Does not print
COMMIT
END TRY
BEGIN CATCH
PRINT @@TRANCOUNT -- Prints 1, transaction is still going
END CATCH
PRINT @@TRANCOUNT -- Prints 1, transaction is still going!
ROLLBACK
この話の教訓は、T-SQL での適切なエラー処理は非常に難しいということです。通常、私にとってうまくいくのは、SET XACT_ABORT ON
重要なステートメントのバッチに対して実行し、トランザクションを SQL Server の外部で (クライアント コードを介して) 開始およびコミットまたはロールバックすることです。これにより、SQL Server がクライアントにエラーを返すと最終的にロールバックが発生するため、トランザクションを停止または破滅させるものとしないものを理解する際の困難の多くが回避されます。しかしもちろん、それでも特効薬ではありません。