【问题标题】:SQL Server Rolls back my transaction when using THROWSQL Server 在使用 THROW 时回滚我的事务
【发布时间】:2015-07-28 20:02:11
【问题描述】:

我的一个表上有一个 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。

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

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

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

在特定情况下,在触发器内设置 XACT_ABORT OFF 会很有用;但您的事务仍会受到一般批处理中止错误(如死锁)的破坏。

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

【问题讨论】:

    标签: sql-server transactions throw


    【解决方案1】:

    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。从最佳实践的角度来看,如果您在触发器中强制执行业务规则而不回滚,那么触发器不是正确的解决方案。

    【讨论】:

    • 好文章 - 谢谢丹。 @usr,触发器必须在数据库级别,它们是扩展约束的一部分。在具有多个客户端(包括 SSIS)的系统中,您无法在任何地方强制执行检查。我的示例没有给出约束检查的全部细节。 Dan 和文章都没有说不要在触发器中抛出错误,他们说不要试图抑制回滚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 2011-04-27
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多