SQL Server在使用THROW时回滚我的事务

Gil*_*ert 6 sql-server transactions 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
Run Code Online (Sandbox Code Playgroud)

如果你运行rollback tran - 它会告诉你没有begin tran.

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

我检查了xact_abort标志 - 它已关闭.

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

任何帮助表示感谢,谢谢.

编辑 阅读@Dan Guzman发表的文章后,我得出以下结论/总结......

SQL Server在触发器中自动设置XACT_ABORT ON.

我的例子(上图)没有说明我的情况 - 实际上我正在使用触发器创建扩展约束.

我的用例是人为的,我试图在SAME单元​​测试中测试多种情况(不是现实世界的情况,而不是良好的单元测试练习).

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

在特定情况的触发器内设置XACT_ABORT OFF会很有用; 但是你的交易仍会受到一般批量中止错误(如死锁)的破坏.

抛开历史原因,我不同意SQL Server对此的处理; 只是因为目前没有您希望继续交易的情况,并不意味着可能不会出现这种情况.我希望看到一个人能够设置SQL Server来维护事务的完整性,如果你选择的架构是在源头严格管理事务,即"他一个人开始交易,必须完成它".除了通常的故障保险之外,例如,如果由于系统故障而永远无法访问您的代码.

Dan*_*man 4

THROWTRY/CATCH当超出( https://msdn.microsoft.com/en-us/library/ee677615.aspx )范围时将终止批处理。这里的含义是不会对批处理进行进一步的处理,包括插入后面的语句。您需要用INSERTa 括起来TRY/CATCH或使用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。从最佳实践的角度来看,如果您在触发器中强制执行业务规则而不进行回滚,那么触发器就不是正确的解决方案。