【发布时间】:2020-01-10 17:13:21
【问题描述】:
我假设在transaction 中未被捕获的throw 会回滚。但是使用此代码进行测试,似乎交易保持打开状态。这是正常行为吗?
begin transaction;
throw 50001, N'Exception', 1;
commit transaction;
我使用这个查询:
select * from sys.sysprocesses where open_tran = 1;
列出交易并查看 1 个打开的交易。一旦我在该连接上运行commit,它就会关闭。
那么,当我 throw 之前,我需要一直 rollback 自己吗?如果其他代码在我的事务中但在我的代码之外抛出怎么办?
通常这不是问题,因为关闭连接会结束它。但是如果我sp_getapplock 绑定到transaction,如果我throw 没有手动rollback,它将保持锁定状态。
【问题讨论】:
-
您描述的行为由 Erland Sommarskog in this article 解释,并要求 XACT_ABORT 为 OFF。批处理已终止,但事务未终止。正如 Erland 解释的那样,仔细的编码和没有长时间运行的事务应该可以减轻这种不幸的行为
-
你为什么使用
sp_getapplock?唯一有效的原因是防止存储过程执行两次。在这种情况下,您必须使用try/catch,而不是让事情顺其自然(也就是环境设置) -
这不是一个有效的用途。对于初学者来说,它不能扩展 - 这就像尝试使用 SERIALIZABLE 来确保原子性 - 限制性太强。其次,不能保证它会像您发现的那样开始工作。如果您搜索,您会找到使用适当的锁定提示(如 TABLOCK 和 HOLDLOCK)来实现具有一定性能的队列的方法,但最后,只有破坏性读取(即 DELETE .... OUTPUT deleted....)才是真正安全的。即便如此,还有更安全、更快的分布式排队选项
-
检查 Remus Rusany 的 this article 使用表作为队列。这是最好的之一。
标签: sql-server tsql