5

這篇文章的根本問題是「爲什麼非升級的LTM事務會有疑問?」在SQL Server 2005上使用System.Transactions的TransactionInDoubtException

我得到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() 

任何想法?爲什麼我會懷疑,當我得到它時我該怎麼做?

編輯更多信息

我其實還沒有爲這個問題的答案。我確實意識到交易實際上部分承諾。一個表獲取插入,但另一個無法獲得更新。該代碼是嚴重追查,並沒有太多的空間讓我失去一些東西。

有沒有一種方法可以輕鬆找出交易是否已被提升。我們可以從堆棧跟蹤中知道它是否是? SIngle階段提交(這是在追蹤軌跡)似乎表明沒有提升給我,但也許我失去了一些東西。如果它沒有得到提升,那麼它怎麼會有疑問。

另一個有趣的難題是我創建了當前事務的克隆。我將其作爲此問題的解決方案。 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(); 
} 

感謝

+0

是數據庫鏡像? – 2009-06-11 22:10:41

+0

否數據庫不鏡像。這也不僅僅發生在一個或兩個環境中,而是發生在其中一兩個環境中 – Mark 2009-06-12 18:23:43

+0

您是否試過在[serverfault](http://serverfault.com/)上詢問?甚至可以向微軟提出一項移交請求。當你發現它時,請發佈答案... – 2009-09-22 13:41:51

回答

2

答案是它不能。顯然發生的是促銷活動正在發生。 (我們意外發現了這一點)我仍然不知道如何檢測升級嘗試是否正在發生。這在檢測這件事上會非常有用。

0

硬盤沒有尋找到你的代碼勸告什麼,但我的第一個建議是,TransactionScope的()是一個開銷,當你有1個連接1臺SQL服務器。

爲什麼不使用System.Data.SqlClient.SqlTransaction()呢?

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

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

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

這個問題是相當古老的,也許你已經知道答案,並可以發佈在這裏爲他人。謝謝!

0

擊敗了我。

我習慣在手動執行「BEGIN TRANSACTION」和「COMMIT」或「ROLLBACK」時執行ExecuteNonQuery。

非常偶然的事情,當一些代碼需要在事務中工作而不管它是否在事務中時,這確實很成功。

0

我實際上有同樣的問題,它似乎與數據庫服務器的規格有關。當你執行這個代碼時,我會讓你的dba看看這個盒子的CPU利用率。這發生在我們的環境中,因爲我們正在嘗試對事務中的數據庫中的大量行進行更新操作。這發生在我們最常用的一個表上的OLTP數據庫上,這會導致鎖爭用。我覺得這個問題令人着迷的是我在堆棧跟蹤中看到的超時方面。無論什麼時候超時值設置,無論是在命令還是作爲TransactionScope構造函數的參數,它似乎都沒有解決問題。我要解決這個問題的方法是將提交分塊。希望這可以幫助

11

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

由於實施單階段提交協議的方式,在事務處理程序向其下級發送SinglePhaseCommit請求之後以及在下級響應之前有一小段時間事務處於「疑問」狀態(承諾/中止/準備)(需要升級/升級到MSDTC)消息。如果在此期間連接丟失,則事務處於「疑問」狀態,因此TransactionManager在要求下級執行SinglePhaseCommit時從未收到響應。

MSDN Single-Phase Commit,也看到這個答案底部的「單階段提交流程」的形象:

有一個可能的缺點,以這種優化:如果 事務管理器失去與下屬參與者 接觸在發送單階段提交請求之後但在收到結果通知之前,它沒有可靠的機制來恢復交易的實際結果。因此,本次交易 管理器發送一個疑問成果的任何應用程序或選民 等待信息的結果通知

而且,這裏是我發現原因System.Transaction促銷/升級到MSDTC的東西一些實際的例子交易(這是沒有直接關係的OP,但我發現非常有用的測試在VS 2013,SQL Server 2008 R2中,.NET 4.5除非另有說明):

  1. (這個人是特定於SQL Server 2005或如果兼容級別< 100) - 在任何點withi上多次調用Connection.Open()一個TransactionScope。這還包括在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. 看來,如果使用連接池,並且連接1中使用的同一確切物理連接由於連接」2到N「中的某種原因而不可用,那麼整個事務將被提升(b/c這些被處理作爲2個單獨的耐用資源,項目#2是下面的MS官方列表)。我沒有測試/確認這個特殊情況,但是我瞭解它是如何工作的。它在幕後很有意義,這與使用嵌套連接類似或不使用連接池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. 至少有一個不支持單階段通知的持久資源是enlis參與交易。
  2. 至少有兩個支持單階段通知的持久資源被列入交易。例如,徵用SQL Server 2005的單一連接不會導致事務被提升。但是,無論何時打開第二個連接到導致數據庫登錄的SQL Server 2005數據庫,System.Transactions基礎結構都會檢測到它是事務中的第二個持久資源,並將其升級爲MSDTC事務。
  3. 調用請求將事務「封送」到不同的應用程序域或不同的進程。例如,跨應用程序域邊界的事務對象序列化。事務對象是按值編組的,這意味着任何跨越應用程序域邊界(即使在同一個進程中)的嘗試都會導致事務對象的序列化。您可以通過在以Transaction爲參數的遠程方法上調用來傳遞事務對象,也可以嘗試訪問遠程事務服務組件。這將對事務對象進行序列化並導致升級,例如事務在應用程序域中被序列化。它正在分發,當地的交易管理器已經不夠了。

Single phase commit flow