2010-01-29 94 views
6

我有一些代碼後插入觸發器可能會失敗。這樣的失敗並不重要,如果不是回滾事務。我怎樣才能將錯誤捕獲到觸發器中並讓事務的其餘部分正常執行?TSQL使觸發器無提示失敗

下面的例子顯示了我的意思。觸發器故意創建一個錯誤條件,結果是原始插入(「1」)永遠不會插入到表中。 Try/Catch似乎沒有辦法。類似的,older stack overflow question沒有得到答案,除了「首先防止錯誤發生」 - 這並不總是可行的。

還有其他想法嗎?

create table test 
(
    a int not null 
); 
go 

create trigger testTrigger on test 
after insert as 
begin 
    insert into test select null; 
end; 
go 

insert into test values (1); 
+1

爲什麼試試/ Catch不工作? – cjk 2010-01-29 15:41:04

+0

@ck:因爲觸發器內部的約束違規不符合事務。 – Quassnoi 2010-01-29 17:11:43

回答

2

觸發器不能失敗,仍然有交易前滾。您有幾個選項來確保觸發器不會失敗。

1 - 你可以確保以後不會通過複製邏輯檢查的約束,而不是試圖這將違反約束的操作失敗:

INSERT INTO test WHERE val IS NOT NULL 

2 - 你可以通過使用隊列設計模式推遲可能失敗的動作,其中可能會或可能不會出現故障的動作通過入隊排隊到排隊操作不可能失敗的表中排隊。

INSERT INTO ACTION_QUEUE (action, parameters) VALUES ('INSERT INTO TEST', val) 
+0

恐怕這是唯一的方法。雖然這很困難。請在下面看到我對Quassnoi的回覆的評論。 – BuschnicK 2010-02-01 16:26:23

+0

@BuschnicK製作觸發器是您可以在系統中進行的更具侵入性的事情之一。它是用於強制執行數據庫行爲的數據庫模式的一部分,並且您正在其他人的數據庫中執行此操作。他們有自己的位置,但我不認爲這種用法是恰當的,如果你不能確保他們的行爲良好。坦率地說,如果您使用觸發器作爲您發佈更改的唯一機制,如果觸發器默默失敗,您的更改將無法發貨,但交易可能會完成,並且您將丟失更改數據「消息」,您將如何無論如何可靠地重新同步您的數據? – 2010-02-01 17:10:43

+0

@BuschnicK您最好查看某種更改數據捕獲或其他ETL技術,以比較自上次快照以來發生的更改。 – 2010-02-01 17:11:37

1

由於觸發器在SQL Server實現的方式,所有違反約束的觸發器中的厄運交易。

這是一樣的做:

DROP TABLE test 

CREATE TABLE test 
(
     a INT NOT NULL 
) 

GO 

SET XACT_ABORT ON 
GO 

BEGIN TRANSACTION 

BEGIN TRY 
     INSERT 
     INTO test 
     SELECT NULL 
END TRY 
BEGIN CATCH 
     INSERT 
     INTO test 
     SELECT 1 
END CATCH 

這會導致註定交易,但沒有辦法禁用XACT_ABORT觸發器內。

SQL Server也缺乏自主交易。

這就是爲什麼您應該將所有邏輯放入存儲過程而不是觸發器的另一個原因。

+0

實際上,如果您不使用try..catch,您不會註定失敗。 – 2010-01-29 19:45:37

+0

@Alex:當然,操作只是原子上取消。這只是爲了演示發生了什麼。 – Quassnoi 2010-01-29 20:37:35

+0

存儲過程如何提供幫助?我想如果有什麼觸發器會調用存儲過程... 要給我一點我想要在這裏實現的背景信息:我們有一個供應商提供的ERP系統,並希望得到實時更新數據它是桌子。我們將觸發器附加到他們的表格中,按摩數據並將其複製到我們自己的數據庫中。我們希望保證我們的觸發器永遠不會失敗,因爲這會導致原始ERP系統出現問題。 – BuschnicK 2010-02-01 16:24:53

0
  1. 您可以打開關閉XACT_ABORT觸發(小心使用)內
  2. 您可以觸發調用存儲過程。 (我現在正面臨着相反的問題:我希望事務中止,但是因爲邏輯是在觸發器中調用的SP中,而不是觸發器本身,所以不會發生。)