2016-07-19 5 views
1

私はSQLServer 2014を使用していますが、IDとvarcharカラムdataを持つ1つのテーブルを持つ単純なデータベースを持っています。SP_ExecuteSQLを使用するとトランザクションが中断される

SET XACT_ABORT ON 
BEGIN TRANSACTION 
    exec sp_executesql N'some nonsense' 
    insert into testTable values ('b') 

COMMIT 

SSMSは私がsp_executesqlコールで間違ったクエリを実行しようとしたため、エラーがあったことを示しています。私は、次のステートメントを実行していくつかの奇妙な振る舞いがあります。ただし、1 row(s) affectedも表示されます。 testTableでselectクエリを実行すると、値 'b'が挿入されていることがわかります。

私はTRY/CATCHブロック内のステートメントをラップした場合、すべてが期待どおりに動作し、トランザクション全体のアクションがロールバックされます。何かが行く場合

BEGIN TRANSACTION 
BEGIN TRY 
    exec sp_executesql N'some nonsense' 
    insert into testTable values ('b') 

    COMMIT 
END TRY 
BEGIN CATCH 
    SELECT ERROR_MESSAGE() 
    ROLLBACK 
END CATCH 

SET XACT_ABORT ONは、トランザクション全体がロールバックされることを保証すべきではありません違う?私は行方不明の設定はありますか?

おかげ

+2

「何かナンセンス」に依存するように見えますが、コンパイル時エラーの場合は、あなたが言うように動作します。実行時エラー( 'exec sp_executesql N'SELECT 1/0 ''のような)の場合、それはあなたが望むように動作します。 –

+0

これは違いがあるかどうかは分かりませんでした。私は構文エラーがあり、それはそれを説明するでしょう。しかし、なぜこれを行うのかを説明するいくつかの文書がありますか?コンパイル時にエラーが発生しても、トランザクション全体がロールバックされるとは思っています。または、XACT_ABORTオプションはランタイムエラーのみを処理しますか? – Pinetree

+0

私はこれまでこれを知らなかった。私はそれが「設計上」であるかどうかわからない。 –

答えて

2

TRY/CATCHに包まれていない実行時の構文エラーがさえONからXACT_ABORT設定して、アクティブなトランザクションをアボートしていないために発生します。どのような状況下で、どのような状況下で、何が中断するのか、そして中止しないのかについての正確なルールは、まったく直接的ではない。 Erland Sommarskogはan excellent write-up on error handling in generalthe rules of what does and doesn't abort in particularです。私はここにすべてのことを再現しませんが、ここでの問題は、その本質に煮詰めます

:実行するだけでなく、停止しない

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は、私たちのためにそれをしない(エラーで)。まだ再び利回り別の何かを、それをオフにするので、これdoomingは、完全に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がクライアントに渡すエラーが最終的にはロールバックになるため、トランザクションを停止したり破棄したりすることを理解することの難しさを回避します。しかし、もちろん、それは銀色の弾丸でもありません。

関連する問題