2012-04-02 3 views
4

私は、挿入/更新/削除時にトリガー内で呼び出されるストアドプロシージャを持っています。トリガーでエラーを無視する

問題は、このSPの内部に特定のコードブロックがあり、重要ではないことです。 したがって、私はこのコードブロックから生じるエラーを無視したいと思います。

このコードブロックをTRY CATCHブロックに挿入しました。しかし、驚いたことに次のエラーが発生しました。

現在のトランザクションはコミットできず、ログファイルに書き込む操作をサポートできません。トランザクションをロールバックします。

それから私は、あまりにも、次のエラーで失敗したことを、TRYのCATCHと一緒にSAVE & ROLLBACKトランザクションを使用してみました:

を現在のトランザクションがコミットすることはできませんし、バックセーブポイントまでロールバックすることはできません。トランザクション全体をロールバックします。

私のサーバーのバージョンがある:のMicrosoft SQL Server 2008(SP2) - 10.0.4279.0(X64)

サンプルDDL:エラーを複製する

IF OBJECT_ID('TestTrigger') IS NOT NULL 
    DROP TRIGGER TestTrigger 
GO 
IF OBJECT_ID('TestProcedure') IS NOT NULL 
    DROP PROCEDURE TestProcedure 
GO 
IF OBJECT_ID('TestTable') IS NOT NULL 
    DROP TABLE TestTable 
GO 

CREATE TABLE TestTable (Data VARCHAR(20)) 
GO 

CREATE PROC TestProcedure  
AS  
BEGIN 

    SAVE TRANSACTION Fallback 
    BEGIN TRY 
     DECLARE @a INT = 1/0 
    END TRY 
    BEGIN CATCH 
     ROLLBACK TRANSACTION Fallback 
    END CATCH 
END 
GO 

CREATE TRIGGER TestTrigger 
ON TestTable 
FOR INSERT, UPDATE, DELETE 
AS 
BEGIN 
    EXEC TestProcedure 
END 
GO 

コード:

BEGIN TRANSACTION 
INSERT INTO TestTable VALUES('data') 
IF @@ERROR > 0 
    ROLLBACK TRANSACTION 
ELSE 
    COMMIT TRANSACTION 
GO 

答えて

1

私はこれを再構築して、元のトランザクションを害さないようにすることをお勧めします。おそらく、トランザクションがサービスブローカーメッセージを送信するようにしてください関連するデータを何らかの形式のキュー表に挿入する)、「重要でない」部分が完全に独立したトランザクションで実行できるようにします。

など。あなたのトリガーは、次のようになります。

CREATE TRIGGER TestTrigger 
ON TestTable 
FOR INSERT, UPDATE, DELETE 
AS 
BEGIN 
    INSERT INTO QueueTable (Col1,Col2) 
    SELECT COALESCE(i.Col1,d.Col1),COALESCE(i.Col2,d.Col2) from inserted i,deleted d 
END 
GO 

あなたあなたはも失敗するトリガー・アクションを開始したトランザクションを強制したいですない限り、失敗する可能性がありますトリガ内の何もしていませ必要があります。

+0

感謝を。実際には、私が話している重要でない部分は、サービスブローカの仕組みを持っています。私は、サービスブローカのメカニズムが失敗したときに、メイントランザクションがロールバックされることを望んでいません。私は現在の実装だけに固執します。ご協力いただきありがとうございます。 – Adi

+0

あなたの最後の声明については.....そうしなければ、トリガーの内部にビジネスロジックコードを直接的にも間接的にも持たないべきですか?もしそうなら、これは人生を非常に難しくしないのですか? – Jami

+1

@サハンド - それは依存しています - この "ビジネスロジック"は、(オプションで)元の*トランザクションを失敗させるべきものですか?そうであれば、それはトリガーに入っていなければなりません(または、外的キーやチェック制約のような他のDRIを通してより直接的に表現される)。代わりに、元の操作が*常に*成功し、この "ビジネスロジック"が分離されているなら、私はこの答えで述べたことに行き、処理を切り離すために何らかの形の待ち行列を使用します。キューに入れられた変更を*読み込む*コードは、あなたが望むほど複雑にすることができます。 –

0

を参照してください。私はあなたがすることができますが、私はそれについてgoogledと私はいくつかの人々は彼らが動作しないと言って見た。 beginトランザクションのために "save transaction"を置き換えた場合、それはコンパイルされます。もちろん、外部のトランザクション制御があり、内部のロールバックがすべてをロールバックするため、必ずしも必要ではありません。

9

私は同じ苦しみを経験していましたが、私はただそれを解決しました! ちょうどあなたのTRIGGERの非常に最初のステップで、この単一の行を追加して、あなたは大丈夫になるだろう:私の場合は

SET XACT_ABORT OFF; 

を、私が引き起こしたバッチと、特定のテーブルを供給し、エラーを処理していますエラーとSQLからのエラー変数。XACT_ABORTため

デフォルト値は ON あるので、あなたは、TRYのCATCHブロック内のエラーを処理している場合でも、トランザクション全体では(私がやっているだけのように)コミットされません。 の値をに設定すると、エラーが発生してもトランザクションがコミットされます。エラーが処理されないとき

しかし、私はより多くの情報については...

それをテストしていない:提案のための

+1

デフォルト値はオンですか?私が見つけることができるすべての情報は、デフォルト値がオフであることを示唆しています –

+0

ドキュメントからは、SQL Server 2008+では、 "OFFがデフォルト設定です。" –