为什么SqlConnection在事务中间关闭?

时间:2015-03-12 07:50:31

标签: .net sql-server transactions transactionscope

在简化后看起来类似于下面的代码conn2.Open(),在事务启动后执行不到1秒(即没有超时问题)有时会抛出,声称(环境)事务已经中止 - 在换句话说,conn2不是问题。

using (var ts1 = new TransactionScope(...))
{
    using (SqlConnection conn1 = new SqlConnection(connStr1))
    {
        conn1.Open();
        var cmd1 = conn1.CreateCommand();
        // use cmd1 .. 
    }

    using (SqlConnection conn2 = new SqlConnection(connStr2))
    {
        conn2.Open(); // THIS SOMETIMES THROWS
        // ...
    }

    ts1.Complete();
}

每次到目前为止发生此异常时,日志都会指示失败的事务和之前的最后一个事务之间至少有4.5分钟而没有任何事务,所以看起来TCP连接可能已超时。

但是,例如conn1已超时,它已经在conn1.Open()。相反,它会抛出conn2.Open(),表示conn1已关闭。

那么conn1发生了什么?为什么?为什么只在致电conn2.Open()

时才会显示

当尝试使用上述代码重现问题时,通过在调用conn1后手动终止conn1.Dispose()下的TCP连接,我可以重现conn2.Open()上几乎完全相同的堆栈跟踪。只有InvalidOperationException变为System.Data.SqlClient.SqlException,其他所有内容都是100%相同。但是在conn1中的活动与成功的conn1.Dispose()conn2.Open()之间几乎没有时间过去,所以它不能超时。

这是

  • WindowsServer 2008R2
  • .Net 3.5
  • SQLServer 2008R2

异常和堆栈跟踪:

System.Transactions.TransactionAbortedException: The transaction has aborted.
 ---> System.Transactions.TransactionPromotionException: Failure while attempting to promote transaction.
 ---> System.InvalidOperationException: The requested operation cannot be completed because the connection has been broken.
   at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlDelegatedTransaction.Promote()
   --- End of inner exception stack trace ---
   at System.Data.SqlClient.SqlDelegatedTransaction.Promote()
   at System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
   at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
   --- End of inner exception stack trace ---
   at System.Transactions.TransactionStateAborted.CheckForFinishedTransaction(InternalTransaction tx)
   at System.Transactions.Transaction.Promote()
   at System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction transaction)
   at System.Transactions.TransactionInterop.GetExportCookie(Transaction transaction, Byte[] whereabouts)
   at System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction transaction, Byte[] whereAbouts)
   at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at My.Code...

修改(解决建议的答案)

可以暂停吗?正如我所提到的,错误发生在事务中不到1秒,因此(没有一些奇怪的错误)它不能是mereTransaction / TransactionScope / DTC超时(它们都设置在30秒以北)。

Fwiw,这是conn1.Dispose()之后和conn2.Open之前的DTC超时(在日语操作系统上)。

System.Transactions.TransactionException: トランザクションの状態に対して操作が有効ではありません。
 ---> System.TimeoutException: トランザクションがタイムアウトしました。
   --- 内部例外スタック トレースの終わり ---
   場所 System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction)
   場所 System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
   場所 System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
   場所 System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
   場所 System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
   場所 System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   場所 System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   場所 System.Data.SqlClient.SqlConnection.Open()

1 个答案:

答案 0 :(得分:1)

您的DTC超时似乎是一个问题,当您说明第二个连接并将事务提升为dtc事务时,它会超时。您可以在机器设置中更改超时。您更改了所有DTC事务的超时,因此在将其更改为较大值时可能会对性能产生影响。

machine.config中超时10分钟:

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