[英]SQL Server errors in trigger that locks table lost with SqlDataAdapter and ambient transaction
好的,所以我遇到了一个相当奇怪的情况。 我的情况有几个层次。 我还没有确定是否严格要求每一层,但这是正在发生的事情:
SqlConnection
自动登记到该事务中。 SqlDataAdapter
将行插入表中。 InsertCommand
引用存储过程。 存储过程是一个简单的INSERT
语句。 INSERT
正在进行的表中有一个触发器INSTEAD OF INSERT
。 使用此连接,C#代码中不会引发错误。 但是,如果触发器未在表上获得独占锁定,则错误确实会影响C#代码。
该错误实际发生的事情,不过,由一个事实,即在SQL Server端,该交易已中止证明。 C#代码不知道事务已中止,并且只在处理TransactionScope
尝试COMMIT TRANSACTION
时遇到错误。
我创建了这种场景的最小复制:
https://github.com/logiclrd/TestErrorWhileLockedInTrigger
有没有人理解为什么会这样,以及如何恢复正确的错误处理行为?
所以,我已经做了更多的测试。
我的第一个想法是,如果持有独占锁是导致它压制错误,也许明确释放锁将会解开它吗? 于是,我把一个TRY
/ CATCH
围绕在我的证明了概念产生错误的语句,有它ROLLBACK TRANSACTION
,然后重新THROW
,但它没有做任何事情。
那么我的下一个想法是, RAISERROR
语句在使用严重级别为20-25时强制终止连接。 我不确定这是否是一个理想的解决方案,因为它会在发生这种情况时写入SQL Server事件日志的条目。 但是,它确实实现了让SqlDataAdapter
在其Update
命令期间看到错误而不是C#代码的目标,认为事务仍处于活动状态并尝试提交它。
有没有人知道这种“大锤”方法的其他潜在缺点,或者它是否可能成为在这种情况下错误传播的唯一方法?
我已经确定了问题的原因。
锁定表的触发器中的语句如下所示:
SELECT TOP 0 *
FROM TableToTriggerAndLock WITH (TABLOCKX, HOLDLOCK)
虽然这不返回任何数据,但它确实返回(空)结果集。 事实证明, SqlDataAdapter
类只关心它在TDS流上返回的第一个结果集,因此第二个结果集中返回的错误完全被传递。
取出锁定语句,然后取出冗余结果集,现在错误出现在第一个结果集中。
那么,解决方案是抑制结果集,我通过将锁定语句重新处理为:
DECLARE @Dummy INT
SELECT TOP 0 @Dummy = 1
FROM TableToTriggerAndLock WITH (TABLOCKX, HOLDLOCK)
希望这可以帮助那些使用SqlDataAdapter
和更复杂的底层操作的人。 :-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.