TransactionScope maximumTimeout

我在这段代码中使用TransactionScope:

private void ExecuteSP() { bool IsComplete = false; SqlCommand sqlComm = null; //6 hours!!! TimeSpan ts1 = new TimeSpan(6, 0, 0); try { using (TransactionScope t = new TransactionScope(TransactionScopeOption.RequiresNew, ts1)) { using (SqlConnection sqlConn = new SqlConnection(GetConnectionString())) { //open sql connection sqlConn.Open(); try { //create new sqlCommand sqlComm = new SqlCommand(); for (int i = 1; i <= 2; i++) { IsComplete = true; //This command takes 15 minutes sqlComm.CommandText = "exec TestSp"; sqlComm.Connection = sqlConn; sqlComm.CommandType = CommandType.Text; sqlComm.CommandTimeout = 18000; //Executing my command int j = sqlComm.ExecuteNonQuery(); } //End t.Complete(); } catch (Exception ex) { IsComplete = false; string Message = ex.Message; } finally { if (sqlComm != null) sqlComm.Dispose(); } } } } catch (Exception ex) { string messagee = ex.Message; //do something } finally { MessageBox.Show("Finsh"); } } 

它发生在一次执行(sqlCommand.ExecuteNonQuery();)后执行超过10分钟。 在这一点上我没有得到任何激励,在下一个例外中,我得到了这个例外:

 The transaction associated with the current connection has completed but has not been disposed. The transaction must be disposed before the connection can be used to execute SQL statements. 

这是因为System.Transactions.TransactionManager.MaximumTimeout设置为TimeSpan为10分钟。

我搜索并发现它可能与“System.Transactions – > machine.config的maxTimeout”有关,但在将配置更改为此文件后出现exception:

            

当我在更改配置文件后尝试在运行时获取System.Transactions.TransactionManager.MaximumTimeout时,我得到此exception:

“配置系统无法初始化”

有没有人知道如何解决这个问题?

(关于我的情况的一般说明:我需要做大约20分钟的存储过程,因为我需要将包含int的表转换为SQL中的bigint(int = 32bit,bigint = 64位)。我需要创建新表并插入使用int64从旧表到新表的数据。通过ID连接到其他4个表的表,每个表包含超过2000万行,还有绑定,索引等等。我不能将此过程拆分为小存储过程所以我需要将最大超时更改为一小时或更长时间,10分钟是不够的!)。

如果您不害怕使用reflection,您实际上可以通过编程方式覆盖最大超时。 此代码不保证是面向未来的,但它适用于.NET 4.0。

 public static class TransactionmanagerHelper { public static void OverrideMaximumTimeout(TimeSpan timeout) { //TransactionScope inherits a *maximum* timeout from Machine.config. There's no way to override it from //code unless you use reflection. Hence this code! //TransactionManager._cachedMaxTimeout var type = typeof(TransactionManager); var cachedMaxTimeout = type.GetField("_cachedMaxTimeout", BindingFlags.NonPublic | BindingFlags.Static); cachedMaxTimeout.SetValue(null, true); //TransactionManager._maximumTimeout var maximumTimeout = type.GetField("_maximumTimeout", BindingFlags.NonPublic | BindingFlags.Static); maximumTimeout.SetValue(null, timeout); } } 

你可以像这样使用它:

  TransactionmanagerHelper.OverrideMaximumTimeout(TimeSpan.FromMinutes(30)); 

您不能在自己的配置文件中指定machineSettings ,但是您需要在计算机的machine.config文件中实际更改/添加machineSettings\maxTimeout

在您的计算机上,每个32/64位和CLR版本组合都有一个此文件实例。 例如,.NET 2.0的32位版本文件位于%windir%\Microsoft.NET\Framework\v2.0.50727\CONFIG目录中。 64位.NET 2.0应用程序的文件位于%windir%\Microsoft.NET\Framework64\v2.0.50727\CONFIG目录中。 同样,如果您使用的是.NET 4.0,则需要更改v4.0.30319\Config子目录中的文件。

请注意,通过更改此文件(名称应该暗示),您可以更改框中每个事务的最大超时。 所以要小心你在这里设置的内容。 在您的示例中,您将超时更改为10(!)小时。

过长的事务超时可能是一个问题,因为有时在达到超时之前无法检测到死锁。 因此,有时无法及时发现这种情况。 还有其他原因可以避免长时间运行的事务,但这实际上超出了这个问题/答案的范围。

无论如何,单个应用程序仍然可以设置自己的最大超时,但是总是被machine.config文件中的超时限制,使用他们自己的配置文件中的system.transactions部分:

     

请注意,此处的元素名称是defaultSettings而不是machineSettings

您还可以查看以下链接以获取更多信息:

我从您的代码中注意到的一件事与MS提供的示例不同的是,您在完成SQL工作之前完成了事务。

例如,

  t.Complete(); 

来之前

  if (sqlComm != null) sqlComm.Dispose(); 

你的t.complete(); 真的需要下移到你的SQL段结束。 我没有运行它来certificate它有效,但它有意义,因为你有一个事务部分,然后在你告诉它完成之后还有进一步的工作。

我用这个作为参考: http : //msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

尝试交换配置文件中元素的顺序,以便appSettings出现在system.transactions之前,如下所示:

  ...   ...  

此外,如果你有configSections ,同样做。

默认值为:

 Transaction Binding=Implicit Unbind. 

隐式取消绑定会导致连接在事务结束时从事务中分离。 在少数情况下,人们使用:

 Binding=Explicit Unbind 

你可以在你的情况下检查这个。

尝试更改“MachineToApplication”的machine.config属性allowExeDefinition:

  

然后,改变你web.config / app.config:

   ...     

属性“maxTimeout”中的值00:00:00(或零)被解释为无穷大。

问候,