TransactionScope TransactionAborted 异常 - 事务未回滚。应该是吗?
(SQL 服务器 2008) 如果 TransactionScope (.Complete()) 内发生事务超时错误,您是否希望事务回滚?
更新:
该错误实际上是在右大括号(即 .Dispose())中引发的,而不是在 .Complete() 中引发的。完整错误是:
The transaction has aborted. System.Transactions.TransactionAbortedException TransactionAbortedException System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.TimeoutException: Transaction Timeout
--- End of inner exception stack trace ---
at System.Transactions.TransactionStateAborted.BeginCommit(InternalTransaction tx, Boolean asyncCommit, AsyncCallback asyncCallback, Object asyncState)
at System.Transactions.CommittableTransaction.Commit()
at System.Transactions.TransactionScope.InternalDispose()
at System.Transactions.TransactionScope.Dispose()
据我所知,事务没有回滚,并且表保持锁定状态,直到我对 SPID/session_id 发出 KILL。
我使用 DBCC OPENTRAN 获取最旧的事务,然后将其杀死。 我尝试过使用状态杀死,但收到一条消息,表示没有可用状态,因为没有任何内容被回滚。 sys.dm_exec_sessions 中 SPID/session_id 的状态为“睡眠”。代码片段:
try
{
using (var transaction = new TransactionScope())
{
LOTS OF WORK CARRIED OUT WITH LINQ ENTITIES/SubmitChanges() etc.
transaction.Complete(); //Transaction timeout
}
return result;
}
catch (Exception ex)
{
logger.ErrorException(ex.Message, ex);
result.Fail(ex.Message);
return result;
}
更新:
问题尚未完全解决,但如果其他人遇到此问题,请提供更多信息。
- 我正在使用 LINQ to SQL,并在事务范围内调用 context.SubmitChanges()。我正在进行很多插入。 SQL Server 探查器指示为每个插入发出单独的 INSERT 语句。
- 在开发中,如果我在调用 SubmitChanges() 之前将线程休眠 60 秒(默认 TransactionScope 超时为 60 秒),那么在调用 TransactionScope.Complete() 时会出现不同的错误(该操作对于事务状态无效。 )。
- 如果我在 .SubmitChaages() 之后和 .Complete() 之前睡了 60 秒,那么我得到 '事务已中止 - System.TimeoutException:事务超时'
- 但请注意,在我的开发计算机上,使用 DBCC opentran 时未找到打开的事务 - 这是您所期望的,因为您期望事务回滚。
- 如果我随后将这个问题底部的代码(抱歉无法让网站将其插入此处)添加到我的配置文件中,这会将 TransactionScope 超时增加到 2 分钟,事情就会再次开始工作(研究表明,如果这不无法工作,machine.config 中可能有一个设置低于优先级)。
- 虽然这将阻止事务中止,但由于更新的性质,这确实意味着核心业务表上的锁定可能长达 2 分钟,因此使用默认 SqlCommand 超时 30 秒的其他选择命令将超时。并不理想,但比坐在那里并完全阻碍应用程序的开放交易要好。
- 几天前,我们发布了一个灾难性的版本,这意味着我们在升级过程中耗尽了磁盘空间(!),因此我们最终使用了收缩数据库功能,这显然会在使用后导致性能问题。
我觉得需要重建数据库并重新思考一些业务功能......
(SQL SERVER 2008)
If a Transaction Timeout error occurs within a TransactionScope (.Complete()) would you expect the transaction to be rolled back?
Update:
The error is actually being thrown in the closing curly brace (i.e. .Dispose()), not .Complete(). Full error is:
The transaction has aborted. System.Transactions.TransactionAbortedException TransactionAbortedException System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.TimeoutException: Transaction Timeout
--- End of inner exception stack trace ---
at System.Transactions.TransactionStateAborted.BeginCommit(InternalTransaction tx, Boolean asyncCommit, AsyncCallback asyncCallback, Object asyncState)
at System.Transactions.CommittableTransaction.Commit()
at System.Transactions.TransactionScope.InternalDispose()
at System.Transactions.TransactionScope.Dispose()
As far as I can tell the transaction is not rolled back and the tables remained locked until I issued a KILL against the SPID/session_id.
I used DBCC OPENTRAN to get the oldest transaction and then KILL it.
I have tried KILL WITH STATUS but get a message that no status is available as nothing is being rolled back. Status of the SPID/session_id in sys.dm_exec_sessions is 'sleeping'. Code snippet:
try
{
using (var transaction = new TransactionScope())
{
LOTS OF WORK CARRIED OUT WITH LINQ ENTITIES/SubmitChanges() etc.
transaction.Complete(); //Transaction timeout
}
return result;
}
catch (Exception ex)
{
logger.ErrorException(ex.Message, ex);
result.Fail(ex.Message);
return result;
}
UPDATE:
Problem is not entirely solved, but further information should anyone else have this problem.
- I am using LINQ to SQL and within the transaction scope I call context.SubmitChanges(). I am carrying out a lot of inserts. SQL Server profiler indicates that a separate INSERT statement is issued for each insert.
- In development, if I sleep the thread for 60 seconds (default TransactionScope timeout is 60 seconds) BEFORE calling SubmitChanges() then I get a different error when calling TransactionScope.Complete() (The operation is not valid for the state of the transaction.).
- If I sleep for 60 seconds AFTER .SubmitChages() and just before .Complete() then I get
'The transaction has aborted - System.TimeoutException: Transaction Timeout' - NOTE however that on my dev machine no open transactions are found when using DBCC opentran - which is what you would expect as you would expect the transaction to rollback.
- If I then add the code at the bottom of this question (sorry couldn't get the website to insert it here) to my config file which increases the TransactionScope timeout to 2 minutes, things start working again (research indicates that if this doesn't work there could be a setting in machine.config that is lower than this that is taking precedence).
- Whilst this will stop the transaction aborting, due to the nature of the updates, it does mean that locks on a core business table could be up to 2 minutes so other select commands using the default SqlCommand timeout of 30 seconds will timeout. Not ideal, but better than an open transaction sitting there and totally holding up the application.
- A few days ago we had a disastrous release that meant we ran out of diskspace mid upgrade (!) so we did end up using the shrink database functionality which apparently can cause performance problems after you have used it.
I feel a rebuild of the database and a rethink of some business functionality coming on...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为 TransactionAbortedException 实际上是超时。如果是这样,您应该会发现 TransactionAbortedException 的 InnerException 是超时。
您应该能够通过确保事务作用域的超时时间比命令超时时间长来摆脱它。
尝试将事务范围更改为如下所示:
并在您的上下文中设置显式超时。应该是这样的:
I'm thinking that the TransactionAbortedException is actually a timeout. If so you should find that the InnerException of the TransactionAbortedException is a timeout.
You should be able to get rid of it by making sure that the timeout of the transactionscope is longer than the command timeout.
Try changing the transaction scope to something like this:
And also set an explicit timeout on your context. Should be something like:
我通过修改“物理文件”machine.config解决了此问题。
1. 您必须本地化文件:
2. 您必须添加以下代码:
I resolve this problem modifying the "physical file" machine.config.
1. You have to localize the file:
2. You have to add the following code: