9

データを変更するためにいくつかのコマンドを実行するストアドプロシージャを作成しました。すべてが成功した場合にのみトランザクションをコミットしたいと思います。私は以下の方法でtry-catchブロックを使用してこれを行っています(実際のCATCHブロックはRAISERRORを使用してエラーメッセージを返します):

BEGIN TRY
  BEGIN TRANSACTION
  UPDATE Table1 SET MyVarcharColumn = 'test'
  UPDATE Table2 SET MyBitColumn = 1
  UPDATE Table3 SET MyIntColumn = 42
  COMMIT TRANSACTION
END TRY
CATCH
  ROLLBACK TRANSACTION
END CATCH

それは私が望むように機能します。たとえば、MyBitColumnを1ではなく'b'に設定すると、エラーがキャッチされ、制御がCATCHに流れ、トランザクションはコミットされません。

私が気付いた問題の1つは、たとえば、Table3がデータベースに存在しない場合、エラーが発生する(オブジェクト名が無効)が、CATCHブロックが実行されず、トランザクションが開いたままになることです。

これを処理して、データベースが変更される(またはこのストアドプロシージャが適切に追加されているが、テーブルの1つが変更されていない)可能性を処理したいと思います。

これらのエラーケースをどのように処理する必要がありますか?

-助けてくれてありがとう。

4

2 に答える 2

12

スクリプトの開始時にSET XACT_ABORTを使用します

SET XACT_ABORT ON

SET XACT_ABORT が ON の場合、Transact-SQL ステートメントで実行時エラーが発生すると、トランザクション全体が終了し、ロールバックされます。

私はそれが可能になるとは思わない:

次のタイプのエラーは、TRY…CATCH 構文と同じ実行レベルで発生した場合、CATCH ブロックによって処理されません。

  • 構文エラーなど、バッチの実行を妨げるコンパイル エラー。

  • 名前解決の遅延が原因でコンパイル後に発生するオブジェクト名解決エラーなど、ステートメント レベルの再コンパイル中に発生するエラー。

参照

次の例は、同じ SELECT ステートメントがストアド プロシージャ内で実行されたときに、SELECT ステートメントによって生成されたオブジェクト名解決エラーが TRY…CATCH 構造によってキャッチされず、CATCH ブロックによってキャッチされる方法を示しています。

USE AdventureWorks2012;
GO

BEGIN TRY
    -- Table does not exist; object name resolution
    -- error not caught.
    SELECT * FROM NonexistentTable;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_MESSAGE() AS ErrorMessage;
END CATCH

エラーは捕捉されず、制御は TRY…CATCH 構造から次の上位レベルに渡されます。

于 2013-02-22T00:55:20.133 に答える