TransactionScope过早完成

我有一个在TransactionScope中运行的代码块,在这个代码块中,我对数据库进行了几次调用。 select,更新,创build和删除整个色域。 当我执行我的删除我执行它使用SqlCommand的扩展方法,将自动重新提交查询,如果它死锁,因为这个查询可能会遇到死锁。

我相信当遇到死锁,并且该函数试图重新提交查询时,会发生此问题。 这是我收到的错误:

与当前连接相关的交易已经完成但尚未处理。 事务必须在连接可以用来执行SQL语句之前进行处理。

这是执行查询的简单代码(下面的所有代码都是在使用TransactionScope的情况下执行的):

using (sqlCommand.Connection = new SqlConnection(ConnectionStrings.App)) { sqlCommand.Connection.Open(); sqlCommand.ExecuteNonQueryWithDeadlockHandling(); } 

以下是重新提交死锁查询的扩展方法:

 public static class SqlCommandExtender { private const int DEADLOCK_ERROR = 1205; private const int MAXIMUM_DEADLOCK_RETRIES = 5; private const int SLEEP_INCREMENT = 100; public static void ExecuteNonQueryWithDeadlockHandling(this SqlCommand sqlCommand) { int count = 0; SqlException deadlockException = null; do { if (count > 0) Thread.Sleep(count * SLEEP_INCREMENT); deadlockException = ExecuteNonQuery(sqlCommand); count++; } while (deadlockException != null && count < MAXIMUM_DEADLOCK_RETRIES); if (deadlockException != null) throw deadlockException; } private static SqlException ExecuteNonQuery(SqlCommand sqlCommand) { try { sqlCommand.ExecuteNonQuery(); } catch (SqlException exception) { if (exception.Number == DEADLOCK_ERROR) return exception; throw; } return null; } } 

错误发生在线上:

 sqlCommand.ExecuteNonQuery(); 

不要忘记从你的TransactionScope中压缩你的select语句。 在SQL Server 2005及更高版本中,即使在使用(nolock)的情况下,仍会在选定的表上创build锁。 检查了这一点,它显示了如何设置和使用TransactionScope 。

 using(TransactionScope ts = new TransactionScope { // db calls here are in the transaction using(TransactionScope tsSuppressed = new TransactionScope (TransactionScopeOption.Suppress)) { // all db calls here are now not in the transaction } } 

我发现,当事务运行的时间超过了System.TransactionsmaxTimeout时,就会出现这个消息。 TransactionOptions.Timeout增加并不重要,它不能超过maxTimeout

maxTimeout的默认值设置为10分钟,其值只能machine.config修改

将以下(在configuration级别中)添加到machine.config以修改超时值:

 <configuration> <system.transactions> <machineSettings maxTimeout="00:30:00" /> </system.transactions> </configuration> 

可以在以下位置findmachine.config: %windir%\Microsoft.NET\Framework\[version]\config\machine.config

你可以阅读更多关于它在这篇博客文章: http : //thecodesaysitall.blogspot.se/2012/04/long-running-systemtransactions.html

我可以重现这个问题。 这是一个事务超时。

 using (new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 0, 1))) { using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (var sqlCommand = connection.CreateCommand()) { for (int i = 0; i < 10000; i++) { sqlCommand.CommandText = "select * from actor"; using (var sqlDataReader = sqlCommand.ExecuteReader()) { while (sqlDataReader.Read()) { } } } } } } 

抛出System.InvalidOperationExceptionexception与此消息:“与当前连接关联的事务已完成但尚未处理,事务必须在连接可用于执行SQL语句之前处置。

为了解决这个问题,可以使查询运行得更快或者延长超时。

如果一个exception发生在一个TransactionScope它将被回滚。 这意味着TransactionScope已经完成。 你现在必须调用dispose()并开始一个新的事务。 老实说,我不确定是否可以重新使用旧的TransactionScope ,我从来没有尝试过,但我不认为。

我的问题是一个愚蠢的,如果你坐在debugging突破超时,你会得到这个。 面对棕榈

男人,编程让你感觉有些日子…

确认此错误也可能是由事务超时造成的。 只要添加到Marcus + Rolf所说的话,如果你没有明确地在TransactionScope上设置超时,那么超时TimeSpan将会默认一个默认值。 这个默认值是以下值中的较小值:

  1. 如果你已经覆盖了本地的app.config / web.config设置,例如

     <system.transactions> <defaultSettings timeout="00:05:00" /> </system.transactions> 
  2. 但是,这是在machine.config设置<machineSettings maxTimeout="00:10:00" />

禁用 Microsoft Distributed Transaction Coordinator器也可能导致此exception。

如果要启用它,我们运行“ dcomcnfg ”并select"Component Services" -> "My Computer" -> "Distributed Transaction Coordinator" -> "Local Service DTC"并select“ 属性 ”。

应该勾选“ 允许远程客户端 ”,“ 允许入站 ”,“ 允许出站 ”和“ 不需要validation ”。