2010-01-29 65 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中,而不是触发器本身,所以不会发生。)