SQL Server在使用THROW

时间:2015-05-17 06:49:51

标签: 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

如果你运行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来维护事务的完整性,如果你选择的架构是在源头严格管理事务,即"他一个人开始交易,必须完成它&#34 34 ;.除了通常的故障保险箱之外,例如,如果由于系统故障而永远无法访问您的代码等。

1 个答案:

答案 0 :(得分:4)

THROW将在TRY/CATCHhttps://msdn.microsoft.com/en-us/library/ee677615.aspx)范围之外终止批处理。这里的含义是不再进行批处理,包括插入后的语句。您需要使用INSERT包围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。从最佳实践的角度来看,如果在没有回滚的情况下在触发器中强制执行业务规则,则触发器不是正确的解决方案。