SQL Server在使用THROW时回滚事务



在我的一个表上有一个INSERT触发器,当它发现重复时发出一个THROW。问题是我的事务似乎在此时隐式回滚-这是一个问题,我想控制事务何时回滚。

这个问题可以用下面的脚本重新创建:

CREATE TABLE xTable (
        id int identity not null
)
go
create trigger xTrigger on xTable after insert as
print 'inserting...';
throw 1600000, 'blah', 1
go
begin tran
insert into xTable default values
rollback tran
go
drop table xTable

如果你运行回滚转换-它会告诉你没有开始转换。

如果我将THROW交换为'正常'异常(如SELECT 1/0),事务不会回滚。

我已经检查了xact_abort标志-它是关闭的。

使用SQL Server 2012并通过SSMS进行测试

任何帮助,感谢。

编辑在阅读了@Dan Guzman的文章后,我得出了以下结论/总结…

SQL Server自动设置XACT_ABORT ON触发器

我的例子(上面)并没有说明我的情况——实际上,我使用触发器创建了一个扩展约束。

我的用例是人为的,我试图在同一个单元测试中测试多种情况(不是真实的情况,也不是好的单元测试实践)。

我对扩展约束检查的处理和在触发器中抛出错误的处理是正确的,但是没有我不想回滚事务的实际情况。

在特定情况下,在触发器内部设置XACT_ABORT OFF是很有用的;但是你的事务仍然会被一般的批处理中止错误(如死锁)破坏。 撇开历史原因不谈,我不同意SQL Server对这个问题的处理;仅仅因为目前没有你想继续交易的情况,并不意味着这种情况不会发生。我希望看到一个能够设置SQL Server来维护事务的完整性,如果你选择的架构是有严格的事务管理在起源,即。"只有开始交易的人,才必须完成交易"。除了通常的故障保护之外,例如,如果由于系统故障等原因,您的代码永远无法到达

THROW将在超出TRY/CATCH (https://msdn.microsoft.com/en-us/library/ee677615.aspx)范围时终止批处理。这里的含义是不会对批处理进行进一步处理,包括插入之后的语句。你需要用TRY/CATCH包围你的INSERT,或者用RAISERROR代替THROW

T-SQL错误处理是一个相当庞大和复杂的主题。我建议您阅读Erland Sommarskog的错误处理系列文章:http://www.sommarskog.se/error_handling/Part1.html。这里最相关的是主题Can I Prevent the Trigger from Rolling Back the Transaction? http://www.sommarskog.se/error_handling/Part3.html#Triggers。从最佳实践的角度来看,如果您在没有回滚的触发器中执行业务规则,则触发器不是正确的解决方案。

最新更新