我的一张桌子上有一个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。
我的示例(上面)没有说明我的情况-实际上,我正在使用触发器创建扩展约束。
我的用例是人为设计的,我试图在SAME单元测试中测试多种情况(不是现实情况,也不是好的单元测试实践)。
我对扩展约束检查的处理并在触发器中引发错误是正确的,但是没有实际情况下我不希望回滚事务。
对于特定情况,在触发器内部将XACT_ABORT OFF设置会很有用;但您的交易仍会受到一般的中止批量错误(例如死锁)的破坏。
除了历史原因,我不同意SQL Server对此的处理。仅仅因为您目前没有想要继续进行交易的情况,并不意味着可能不会出现这种情况。我希望看到一种能够设置SQL Server来维护事务完整性的方法,如果您选择的体系结构是从源头严格管理事务,即“启动事务的人必须完成它”。除了通常的故障保护之外,例如,由于系统故障而导致无法访问您的代码等。
THROW
将不在TRY/CATCH
(https://msdn.microsoft.com/zh-cn/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。从最佳实践的角度出发,如果在触发器中执行业务规则而没有回滚,则触发器不是正确的解决方案。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句