簡體   English   中英

使用SQL Server 2005上的System.Transactions的TransactionInDoubtException

[英]TransactionInDoubtException using System.Transactions on SQL Server 2005

這篇文章的基本問題是“為什么非升級的LTM交易會受到質疑?”

我收到System.Transactions.TransactionInDoubtException,我無法解釋原因。 不幸的是我無法重現這個問題,但根據跟蹤文件它確實發生了。 我正在使用SQL 2005,連接到一個數據庫並使用一個SQLConnection,所以我不希望進行促銷。 錯誤消息表示超時。 但是,有時我得到一條超時消息,但異常是事務已中止而不是有疑問,這更容易處理。

這是完整的堆棧跟蹤:

System.Transactions.TransactionInDoubtException: The transaction is in doubt. ---> System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
   at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
   at System.Data.SqlClient.TdsParserStateObject.ReadBuffer()
   at System.Data.SqlClient.TdsParserStateObject.ReadByte()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
   at System.Data.SqlClient.SqlDelegatedTransaction.SinglePhaseCommit(SinglePhaseEnlistment enlistment)
   --- End of inner exception stack trace ---
   at System.Transactions.TransactionStateInDoubt.EndCommit(InternalTransaction tx)
   at System.Transactions.CommittableTransaction.Commit()
   at System.Transactions.TransactionScope.InternalDispose()
   at System.Transactions.TransactionScope.Dispose()

有任何想法嗎? 為什么我會懷疑,當我得到它時我該怎么辦?

編輯以獲取更多信息

我實際上仍然沒有這個答案。 我所意識到的是,交易實際上是部分提交的。 一個表獲取插入但另一個表未獲得更新。 代碼是HEAVILY跟蹤,沒有太多空間讓我錯過一些東西。

有沒有辦法可以輕松找出交易是否已被提升。 我們可以從堆棧跟蹤中判斷它是否存在? 單一階段提交(在strack trace中)似乎表明沒有向我推廣,但也許我錯過了一些東西。 如果它沒有得到提升那么它怎么會有疑問。

這個難題的另一個有趣的部分是我創建了當前事務的克隆。 我這樣做是為了解決這個問題。 http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=914869&SiteID=1

不幸的是,我不知道這個問題是否已經解決。 也許創建克隆會導致問題。 這是相關的代碼

using (TransactionScope ts = new TransactionScope())
{
   transactionCreated = true;
   //part of the workarround for microsoft defect mentioned in the beginning of this class
   Transaction txClone = Transaction.Current.Clone();
   transactions[txClone] = txClone;
   Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(TransactionCompleted);
   MyTrace.WriteLine("Transaction clone stored and attached to event");

   m_dataProvider.PersistPackage(ControllerID, package);
   MyTrace.WriteLine("Package persisted");
   m_dataProvider.PersistTransmissionControllerStatus(this);
   MyTrace.WriteLine("Transmission controlled updated");
   ts.Complete();
}

謝謝

目前接受的答案是,非升級的LTM(非MSDTC)交易永遠不會有疑問。 經過對類似問題的大量研究后,我發現這是不正確的。

由於單階段提交協議的實現方式,在事務管理器將SinglePhaseCommit請求發送給其下級之后,以及在下級回復之前,事務處於“懷疑”狀態的時間很短。中止/或准備(需要推廣/升級到MSDTC)消息。 如果在此期間連接丟失,則事務處於“不確定”狀態,b / c當TransactionManager要求下屬執行SinglePhaseCommit時,它從未收到響應。

MSDN單階段提交 ,還可以在此答案的底部看到“單階段提交流”圖像:

這種優化有一個可能的缺點:如果事務管理器在發送單階段提交請求之后但在接收結果通知之前失去與下級參與者的聯系,則它沒有可靠的機制來恢復事務的實際結果。 因此,事務管理器向等待信息結果通知的任何應用程序或選民發送In Inouboub結果

這里還有我發現的一些實際例子,它們會導致System.Transaction升級/升級到MSDTC事務(這與OP沒有直接關系,但我發現它非常有用。在VS 2013中測試過,SQL Server 2008 R2 ,.NET 4.5除非另有說明):

  1. (這個特定於SQL Server 2005或兼容級別<100) - 在TransactionScope中的任何位置多次調用Connection.Open()。 這還包括在SAME連接實例上調用.Open(),. Close(),. Open()。
  2. 在TransactionScope中打開嵌套連接
  3. 使用不使用連接池的多個連接,即使它們未嵌套並連接到同一數據庫。
  4. 涉及鏈接服務器的查詢
  5. 使用TransactionScope的SQL CLR過程。 請參閱: http//technet.microsoft.com/en-us/library/ms131084.aspx “只有在訪問本地和遠程數據源或外部資源管理器時才應使用TransactionScope。這是因為TransactionScope [在CLR內]始終導致事務促進 ,即使它僅在上下文連接中使用“
  6. 似乎如果使用連接池,並且Connection1中使用的相同的物理連接由於某種原因在Connections“2到N”中不可用,則整個事務將被提升(b / c這些被視為2個單獨持久的資源,項目#2是下面的MS官方列表)。 我沒有測試/確認這個特例,但是我對它是如何工作的理解。 它在后台有意義b / c這類似於使用嵌套連接或不使用連接池b / c使用多個物理連接。 http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.110).aspx “當一個連接被關閉並返回到具有登記的System.Transactions事務的池中時,它被放在一邊這樣一種方式,即具有相同System.Transactions事務的連接池的下一個請求將返回相同的連接(如果可用)。如果發出此類請求,並且沒有可用的池連接,則從非連接中提取連接 - 游泳池的相關部分並入伍“

以下是導致升級的MS正式列表: http//msdn.microsoft.com/en-us/library/ms229978( v = vs。85).aspx

  1. 在事務中登記至少一個不支持單階段通知的持久資源。
  2. 在事務中登記至少兩個支持單階段通知的持久資源。 例如,與SQL Server 2005建立單個連接不會導致事務被提升。 但是,每當打開導致數據庫登記的SQL Server 2005數據庫的第二個連接時,System.Transactions基礎結構都會檢測到它是事務中的第二個持久資源,並將其升級為MSDTC事務。
  3. 調用將事務“編組”到不同應用程序域或不同進程的請求。 例如,跨應用程序域邊界的事務對象的序列化。 事務對象是按值封送的,這意味着任何嘗試將其傳遞到應用程序域邊界(即使在同一進程中)都會導致事務對象的序列化。 您可以通過對以事務作為參數的遠程方法進行調用來傳遞事務對象,也可以嘗試訪問遠程事務服務組件。 這會序列化事務對象並導致升級,就像跨應用程序域序列化事務一樣。 它正在分發,本地事務管理器已不再適用。

單階段提交流程

答案是它不能。 顯然正在發生的是促銷活動正在進行中。 (我們意外地發現了這一點)我仍然不知道如何檢測促銷嘗試是否正在發生。 在檢測到這一點時,這本來就非常有用。

很難在沒有查看代碼的情況下給出任何建議,但我的第一個建議是,如果你有一個帶有1個連接的SQL服務器,則TransactionScope()是一個開銷。

為什么不使用System.Data.SqlClient.SqlTransaction()呢?

文檔sais“如果在數據庫事務中打開了與遠程服務器的連接,則與遠程服務器的連接將被登記到分布式事務中,並且本地事務將自動提升為分布式事務。” 但是,如果你真的只使用一個連接是一個非常奇怪的錯誤。 您確定沒有調用任何可以創建與MS SQL,MS MQ或其他需要創建分布式事務的連接的第三方組件嗎?

此外,如果您在SQL Server CLR過程中使用TransactionScope(),它將在任何情況下提升事務。

此外,如果您調用從鏈接的SQL服務器訪問表的存儲過程,我想這也需要升級。

這個問題已經很老了,也許你已經知道了答案,可以在這里發布給其他人。 謝謝!

打敗了我。

我習慣用“BEGIN TRANSACTION”和“COMMIT”或“ROLLBACK”手工執行ExecuteNonQuery。

很明顯,當一些代碼需要工作時,無論是否處於事務中,這都非常有效。

我實際上遇到了同樣的問題,它似乎與數據庫服務器的規格有關。 在執行此代碼時,我希望您的dba可以查看該框的CPU利用率。 這發生在我們的環境中,因為我們正在對事務中的數據庫中的大量行嘗試更新操作。 這種情況發生在我們最常用的表之一的OLTP數據庫上,這會產生鎖爭用。 我發現這個問題引人入勝的是我在堆棧跟蹤中看到的超時方面。 無論你設置的是什么超時值,無論是在命令上還是作為TransactionScope構造函數的參數,它似乎都沒有解決問題。 我要解決這個問題的方法是對提交進行分塊。 希望這可以幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM