【发布时间】:2020-10-09 16:02:47
【问题描述】:
我在表上使用更新后触发器纯粹是为了测试目的,以便强制 SSIS 包出错。它基本上只是一个触发器,在更新发生后使用静态消息调用RAISERROR()。
这在大多数情况下都可以正常工作。但是,当我调用包含 try/catch(不涉及显式事务)的特定存储过程并更新表时,更新不会发生或以某种方式回滚。我对 Try/Catch 的理解是,除非您明确实现 BEGIN/COMMIT/ROLLBACK TRANSACTION,否则它不会回滚。
我似乎误解了 Try/Catch,或者我误解了触发器的功能。我通常尽量不使用触发器,但对于这个用例来说它是有意义的。
如果我注释掉 Try/Catch,一切都会按我的预期运行。
CREATE PROCEDURE dbo.MySproc
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
UPDATE dbo.MyTableToFireTrigger SET SomeColumn = 1 WHERE SomeColumn = 0
END TRY
BEGIN CATCH
--I'm able to log the after update trigger error message here, but it seems to be rolling back the update.
END CATCH;
END
触发器创建:
CREATE TRIGGER dbo.MyTrigger ON dbo.MyTableToCauseTrigger
AFTER UPDATE
AS
BEGIN
RAISERROR('Error', 16, 1);
END;
【问题讨论】:
-
为什么要使用
RAISERROR(),至少从 SQL Server 2012 开始就已经推荐了THROW(包括在文档中)。至于为什么它不起作用,请花时间向我们提供minimal reproducible example。例如,我们这里没有触发器或表的 DDL。 -
这只是为了测试目的,可能永远不会再使用了。如果 RAISERROR() 导致我的问题而 THROW 不会有特定原因,我很想听听。
-
这不需要最小的可重现示例。这只是功能问题。代码没有损坏,它适用于没有 Try/Catch 的存储过程,如果我删除 Try/Catch,它也适用于这个存储过程。我敢肯定有人知道这种行为。我试过谷歌搜索,但一切似乎都引用了明确的交易。
-
他们确实有不同的行为
XACT_ABORT在触发器中隐式启用。RAISERROR不被XACT_ABORT尊重,但THROW是。不知道为什么CATCH块会有所作为 -
行为差异的原因是当
XACT_ABORT是ON并且在try块中发生错误并且无法提交(XACT_STATE是@987654336 @)。如果你真的需要这种奇怪的行为,你可以在触发器中SET XACT_ABORT OFF;
标签: sql-server tsql sql-server-2016