3

我在 INSERT TRIGGER 之后创建了

现在,如果在执行触发器时发生错误。它不应该影响对触发表的插入操作。

一言以蔽之,如果触发器中出现任何错误,则应忽略它。

正如我所使用的

BEGIN TRY

END TRY
BEGIN CATCH

END CATCH

但它给出以下错误消息并在触发表上回滚插入操作

触发器执行期间引发错误。批处理已中止,并且用户事务(如果有)已回滚。

4

3 回答 3

5

有趣的问题。默认情况下,触发器的设计是如果它们失败,它们会回滚触发它的命令。因此,只要触发器正在执行,就会有一个活动事务,无论外部是否有显式的 BEGIN TRANSACTION。而且触发器内部的 BEGIN/TRY 也不起作用。您的最佳做法是不要在触发器中编写任何可能失败的代码 - 除非希望触发语句也失败。

在这种情况下,要抑制这种行为,有一些解决方法。

选项A(丑陋的方式):

由于事务在触发器开始时处于活动状态,您可以直接COMMIT使用它并继续执行您的触发器命令:

CREATE TRIGGER tgTest1 ON Test1 AFTER INSERT
AS
BEGIN
COMMIT;
... do whatever trigger does
END;

请注意,如果触发代码中有错误,这仍会产生错误消息,但Test1表中的数据已安全插入。

选项B(也很丑):

您可以将代码从触发器移动到存储过程。然后从实现的 Wrapper SP 调用该存储过程,BEGIN/TRY最后从触发器调用 Wrapper SP。INSERTED如果在逻辑中需要(现在在 SP 中),从表中移动数据可能有点棘手- 可能使用一些临时表。

SQLFiddle 演示

于 2013-07-18T13:23:07.653 回答
2

你不能,任何解决它的尝试都是蛇油。再多的 TRY/CATCH 或 @@ERROR 检查都无法解决根本问题。

如果您想使用触发器的紧密耦合,那么您必须接受耦合导致的较低可用性。

如果你想保持可用性(即插入成功),那么你必须放弃耦合(移除触发器)。您必须在INSERT 提交开始的单独事务中执行您计划在触发器中执行的所有处理。轮询表中新插入的行的 SQL 代理作业、Service Broker 启动的过程甚至是应用程序层步骤都将符合要求。

于 2013-07-18T13:29:35.273 回答
1

接受的答案选项 A 给了我以下错误:“事务在触发器中结束。批次已中止。”。我通过使用下面的 SQL 规避了这个问题。

CREATE TRIGGER tgTest1 ON Test1 AFTER INSERT
AS
BEGIN
    SET XACT_ABORT OFF
    BEGIN TRY  
        SELECT [Column1] INTO #TableInserted FROM [inserted]
        EXECUTE sp_executesql N'INSERT INTO [Table]([Column1]) SELECT [Column1] FROM #TableInserted'
    END TRY  
    BEGIN CATCH
    END CATCH
    SET XACT_ABORT ON
END
于 2019-01-21T16:25:41.453 回答