我在 INSERT TRIGGER 之后创建了
现在,如果在执行触发器时发生错误。它不应该影响对触发表的插入操作。
一言以蔽之,如果触发器中出现任何错误,则应忽略它。
正如我所使用的
BEGIN TRY
END TRY
BEGIN CATCH
END CATCH
但它给出以下错误消息并在触发表上回滚插入操作
触发器执行期间引发错误。批处理已中止,并且用户事务(如果有)已回滚。
我在 INSERT TRIGGER 之后创建了
现在,如果在执行触发器时发生错误。它不应该影响对触发表的插入操作。
一言以蔽之,如果触发器中出现任何错误,则应忽略它。
正如我所使用的
BEGIN TRY
END TRY
BEGIN CATCH
END CATCH
但它给出以下错误消息并在触发表上回滚插入操作
触发器执行期间引发错误。批处理已中止,并且用户事务(如果有)已回滚。
有趣的问题。默认情况下,触发器的设计是如果它们失败,它们会回滚触发它的命令。因此,只要触发器正在执行,就会有一个活动事务,无论外部是否有显式的 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 中),从表中移动数据可能有点棘手- 可能使用一些临时表。
你不能,任何解决它的尝试都是蛇油。再多的 TRY/CATCH 或 @@ERROR 检查都无法解决根本问题。
如果您想使用触发器的紧密耦合,那么您必须接受耦合导致的较低可用性。
如果你想保持可用性(即插入成功),那么你必须放弃耦合(移除触发器)。您必须在INSERT 提交后开始的单独事务中执行您计划在触发器中执行的所有处理。轮询表中新插入的行的 SQL 代理作业、Service Broker 启动的过程甚至是应用程序层步骤都将符合要求。
接受的答案选项 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