82

我在使用TransactionScope将多个数据库查询包装到一个事务中时遇到了问题,我正在使用批处理大小为 500 的 SqlBulkCopy。当我将批处理大小增加到 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();
    }
}
4

7 回答 7

148

这可能在事务超时时发生。您可以像这样增加事务的超时时间(使用适合预期事务长度的值)。下面的代码是 15 分钟:

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

这就是为什么它可能适用于批量大小 500 而不是 1000。

于 2013-01-29T16:35:19.970 回答
27

我发现在 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

于 2014-01-22T05:25:32.660 回答
8

移出街区scope.Complete();connection

using (var scope = new TransactionScope())
{
  using (var connection = (SqlConnection)customerTable.OpenConnection())
   {
    //
   }
  scope.Complete();
}
于 2012-07-12T13:44:10.357 回答
2

超时问题非常明显,但是如果将 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

于 2018-07-27T15:10:39.147 回答
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/

于 2018-02-05T10:04:08.680 回答
0

应用这个:

TransactionScope(TransactionScopeOption.Required, new System.TimeSpan(0, 30, 0));
(0, 30, 0) = (hour,minute,seconds)

如果你想测试,用这个 (0, 0, 1) 应用时间跨度,试试你会得到错误。之后,增加秒或分钟或小时并尝试。它会起作用的。

于 2021-10-20T11:22:12.653 回答
-1

C# 9 朗版本。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;
 }
于 2020-08-12T12:06:04.257 回答