TSQL使触发器无声地失败

时间:2010-01-29 15:34:52

标签: sql-server tsql sql-server-2008 error-handling triggers

我在后插入触发器中有一些可能会失败的代码。这样的故障并不重要,应该回滚事务。如何将错误捕获到触发器中并使事务的其余部分正常执行?

以下示例显示了我的意思。触发器故意创建一个错误条件,结果原始插入(“1”)从不插入表中。尝试/ 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 );

3 个答案:

答案 0 :(得分:2)

触发器不会失败并且仍然有事务前滚。您有几个选项可以确保触发器不会失败。

1 - 您可以通过复制用于检查约束的逻辑并且不尝试违反约束的操作来确保after不会失败:

即。

INSERT INTO test WHERE val IS NOT NULL

2 - 您可以使用队列设计模式推迟可能失败的操作,其中可能会或可能不会失败的操作通过排队到排队操作不可能失败的表来排队。

即。

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

答案 1 :(得分: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也缺乏自主交易。

这就是为什么你应该将所有逻辑放入存储过程而不是触发器的另一个原因。

答案 2 :(得分:0)

  1. 您可以在触发器内关闭XACT_ABORT(请谨慎使用)
  2. 您可以让触发器调用存储过程。 (我现在正在努力解决相反的问题:我希望事务中止,但因为逻辑是在触发器调用的SP中,而不是触发器本身,所以不会发生这种情况。)