错误-与当前连接关联的事务已完成但尚未处理


74

我一直TransactionScope难以使用来将多个数据库查询包装到一个事务中,我正在将SqlBulkCopy使用批处理大小为500。当我将批处理大小增加到1000时,出现了错误:

与当前连接关联的事务已完成,但尚未处理。必须先处理事务,然后才能使用该连接执行SQL语句。

这是我正在使用的代码:

using (var scope = new TransactionScope())
{
    using (var connection = (SqlConnection)customerTable.OpenConnection())
    {
        var table1BulkCopy = new SqlBulkCopy(connection)
        {
            BatchSize = BATCH_SIZE,
            DestinationTableName = TableName1
        };

        table1BulkCopy.WriteToServer(table1DataTable);

        var table2BulkCopy = new SqlBulkCopy(connection)
        {
            BatchSize = BATCH_SIZE,
            DestinationTableName = TableName2
        };

        table2BulkCopy.WriteToServer(table2DataTable);

        var table3BulkCopy = new SqlBulkCopy(connection)
        {
            BatchSize = BATCH_SIZE,
            DestinationTableName = TableName3
        };

        table1BulkCopy.WriteToServer(table3DataTable);

        var table4BulkCopy = new SqlBulkCopy(connection)
        {
            BatchSize = BATCH_SIZE,
            DestinationTableName = TableName4
        };

        table4BulkCopy.WriteToServer(table4DataTable);

        scope.Complete();
    }
}

Answers:


132

当事务超时时,可能会发生这种情况。您可以像这样增加事务的超时时间(使用适合您期望的事务长度的值)。下面的代码持续15分钟:

using (TransactionScope scope = 
             new TransactionScope(TransactionScopeOption.Required, 
                                   new System.TimeSpan(0, 15, 0)))
  {
      // working code here
  }

这就是为什么它可以用于批量大小500而不是1000的原因。


3
我正在使用Timeout = TransactionManger.MaximumTimeout,所以这不是发生此错误的唯一方法。
Eric J.

这个答案解决了我遇到的一个问题。正如@Eric J提到的,它不是发生此错误的唯一方法,但是如果您的事务超时,您的确会收到上面不相关的消息。
b0redom 2014年

@Pradeep这是正确的答案,应标记为正确答案。
Kiquenet '17

令人敬畏的解释并且非常有帮助
Radhe Sham

这解决了我的问题,原来该操作太过严格,并且该事务在该块中执行所有保存/更新操作之前都已过期...
Niklas

23

我发现在TransactionScope中设置超时对我不起作用。我还需要在machine.config<configuration>标记的末尾添加以下配置键,以延长默认的最大超时时间10分钟。

<system.transactions>
    <machineSettings maxTimeout="00:30:00" /> <!-- 30 minutes -->
</system.transactions>

图片来源:http//thecodesaysitall.blogspot.com.au/2012/04/long-running-systemtransactions.html


1
请注意,必须将其放在config部分的末尾,否则将从IIS中收到错误消息。
Shaul Behr

8

移动scope.Complete();connection块外。

using (var scope = new TransactionScope())
{
  using (var connection = (SqlConnection)customerTable.OpenConnection())
   {
    //
   }
  scope.Complete();
}

这里更多信息为什么?将调用作为using块中的最后一条语句是一种很好的做法。有关该方法的详细信息
天使

1

完整答案必须更完整。

您必须在.Net代码或服务器配置中指定-确定最大事务超时的位置。

<sectionGroup name="system.transactions".... 
    ...allowDefinition="MachineOnly"
</sectionGroup>

在这种情况下,您可以在machine.config中设置最大超时

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

或者,您可能想在应用程序中覆盖此行为。然后,在machine.config中,应设置属性:

...allowDefinition="MachineToApplication"

这是一个很好的细节:https : //blogs.msdn.microsoft.com/ajit/2008/06/18/override-the-system-transactions-default-timeout-of-10-minutes-in-the-code/


1

超时问题很明显,但是如果将TransactionOptions.Timeout设置得更高,则不会生效。即使您设置TimeSpan.MaxValue,您实际上也不会获得利润。不必将TransactionOptions的Timeout属性设置为更高的值,TransactionOptions.Timeout不能超过maxTimeout属性。您应该在machine.config中进行一些更改。

不久,您应该找到machine.config文件%windir%\ Microsoft.NET \ Framework \ yourversion \ config \ machine.config
并将其添加到<configuration>标记中:

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

在这里,您可以将maxTimeout属性设置为30分钟。
请参阅以下详细信息http://thecodesaysitall.blogspot.com/2012/04/long-running-systemtransactions.html


0

C#9 Lang版本。TransactionScopeOption.Suppress对我来说就像魔术一样。

// TransactionScopeOption.Suppress works and fixed my issue
using TransactionScope Scope = new TransactionScope(TransactionScopeOption.Suppress);
try
{
    using var CentralConnection = SQLConnection("Other connection string here");
    using var LocalConnection = SQLConnection("Other connection string here");

    // Central
    using var cmd0 = new SqlCommand("OtherSQLCommandTextHere", CentralConnection)
    {
         CommandTimeout = 0 // I just add zero timeout here
    };
    cmd0.ExecuteNonQuery();

    // Local
    using var cmd1 = new SqlCommand("OtherSQLCommandTextHere", LocalConnection)
    {
         CommandTimeout = 0 // I just add zero timeout here
    };
    cmd1.ExecuteNonQuery();

    // The Complete method commits the transaction. If an exception has been thrown,
    // Complete is not called and the transaction is rolled back.
    Scope.Complete();
}
catch (Exception ex)
{
    Scope.Dispose();
    MessageBox.Show(ex.ToString());
}

public SqlConnection SQLConnection(string ISQLConnection)
{
     SqlConnection conn = null;
     try
     {
         conn = new SqlConnection(ISQLConnection);
         conn.Open();            
     }
     catch 
     {
         // skipping here error message
     }
     return conn;
 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.