在简化后的代码中,类似以下代码
到目前为止,每次出现此异常时,日志都表明在失败的事务和其之前的最后一个事务之间至少有4.5分钟没有任何事务,因此看起来可能是TCP连接超时了。
但是,如果例如conn1已超时,则会在conn1.Open()上抛出异常。相反,它会在conn2.Open()上抛出异常,表明conn1已被关闭。
那么,conn1发生了什么?为什么只在调用conn2.Open()时才指示它?
当尝试使用上面的代码重现问题时,通过在调用conn1.Dispose()后手动终止支持conn1的TCP连接,我几乎可以在conn2.Open()上重现完全相同的堆栈跟踪。只有InvalidOperationException变成了System.Data.SqlClient.SqlException,其他所有内容都是100%相同的。但是,在conn1的活动和成功的conn1.Dispose()和conn2.Open()之间几乎没有时间经过,因此它不能是超时。
这是在:
WindowsServer 2008R2 .Net 3.5 SQLServer 2008R2
异常和堆栈跟踪:
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.Dispose()后手动终止支持conn1的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秒钟的时间内,因此(除非存在一些奇怪的 bug),它不可能仅仅是事务/事务范围/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()