在简化的代码中,类似于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秒之内,因此(没有一些奇怪的错误)不能仅仅是TransTransaction / TransactionScope / DTC超时(都设置在30秒以内)。

    首先,这是conn1.Dispose()之后和conn2.Open之前(在日语OS上)的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()
    

    最佳答案

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

    machine.config中的10分钟超时:

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

    关于.net - 为什么SqlConnection在交易中间会关闭?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29004390/

    10-11 14:06