TransactionAbortedException -你可以安全地重新运行
本文关键字:安全 重新运行 TransactionAbortedException | 更新日期: 2023-09-27 18:14:03
我以以下方式使用TransactionScope
using (var scope = new TransactionScope())
{
using (var conn = SQLHelpers.GetSQLConnection())
{
//commands here
}
scope.Complete();
}
有时我在调用scope.Complete()
时得到TransactionAbortedException
,因为事务已经回滚,并且我已经使用分析器来确定问题是死锁。
异常事务(进程ID 59)在锁资源上与另一个进程发生死锁,并被选为死锁受害者。重新运行事务。
我已经找到了死锁的原因,但是它让我想知道为什么这个错误没有上升到TransactionAbortedException
,所以我确实可以重新运行事务,只是为了这个特定的情况。内部异常不包含任何可以指示实际错误是什么的信息。
检测TransactionAbortedException
作为重新运行事务的原因是否安全?
1)死锁2)超时
3) '连接已关闭'
4) . .
似乎只适合在其中一种情况下重新运行事务,但是如果您保证回滚,则可以将其推广到所有情况。这个问题可以重新表述为"TransactionAbortedException是否保证事务被回滚?"
这个问题可以重新表述为问"do a ?TransactionAbortedException保证事务被滚动回来的?
TransactionAbortedException
的文档说:
当尝试对事务执行操作时抛出此异常已经被回滚,例如,当您尝试在一个已经超时的事务上调用
Commit
方法。方法提交时也会引发此异常事务和事务中止。这是一个可恢复的错误。
我认为这是非常清楚的,从这个描述,如果你捕捉到这个异常,你的事务没有成功完成由于某种原因。我对文档的理解是:"无论事务试图做什么更改,都没有提交给数据库"。
"这是一个可恢复的错误",因此,如果事务的性质使得重试它是有意义的,那么您应该在捕获此异常后重试它。
您可能希望在重试周围引入一些逻辑,例如在重试之前等待一段时间。并随着重试尝试次数的增加而增加等待时间。限制重试的总次数或总重试时间,并在所有重试尝试失败时做一些合理的/优雅的失败。
这个问题来晚了,但我正在研究类似的问题。
有几件事你需要考虑
- 是嵌套事务的这一部分
- 可能是在未来。
- 是否有异步事务正在运行。
如果内部事务重新运行,则外部事务的状态可能已经被泄露了。很容易测试。
-
创建嵌套事务,
-
debug stop at inner transaction.
-
打开sql server,锁住内部事务使用的表
-
运行内部事务并等待死锁。
-
在收到transactionabted Exception后,返回sql server并释放锁
-
返回并重新运行内部事务。
-
检查内部事务状态
-
在尝试提交外部事务之前检查外部事务的状态。