2011-06-19 71 views
1

我在C#應用程序的交易中遇到了MSDTC異常。其功能是在從csv文件讀取數據後,上傳一個十萬條(十萬條)的郵政編碼記錄到數據庫表中。該操作在大約20個批量數據庫操作中完成(每個批次包含5000個記錄)。如果我不使用事務,那麼功能工作正常。在交易過程中的MSDTC異常:C#

有趣的部分是,使用交易的其他功能能夠完成他們的交易。這導致我認爲異常信息是一種誤導性的假設。

有什麼想法可能是什麼問題?

例外:「分佈式事務管理器(MSDTC)的網絡訪問已被禁用。請啓用DTC使用組件服務管理工具在安全配置網絡接入的MSDTC。」

來源:System.Transactions的

內部異常:「事務管理器已禁用其遠程/網絡事務的支持。 (來自HRESULT的異常:0x8004D024)「

注意:事務內部有一個for循環。它是否導致任何問題?

實際要求是:郵編表中有一些現有的郵編。管理員每個月都會上傳新的zipcode csv文件。插入來自csv的新項目。在csv中不可用的郵政編碼(但存在於數據庫中)被認爲是退役並將被刪除。已退役的郵政編碼列表將被退回到用戶界面。新增加的郵政編碼也需要退回。

private void ProcessZipCodes(StringBuilder dataStringToProcess, int UserID) 
    { 
     int CountOfUnchangedZipCode = 0; 
     string strRetiredZipCode = ""; 
     string strNewZipCode = ""; 
     dataStringToProcess.Remove(dataStringToProcess.Length - 1, 1); 

     if (dataStringToProcess.Length > 0) 
     { 

      List<string> batchDataStringList = GetDataStringInBatches(dataStringToProcess); 

      //TimeSpan.FromMinutes(0) - to make transaction scope as infinite. 
      using (TransactionScope transaction = TransactionScopeFactory.GetTransactionScope(TimeSpan.FromMinutes(0))) 
      { 

       foreach (string dataString in batchDataStringList) 
       { 
        PerformDatabaseOperation(dataString, UserID); 
       } 

       transaction.Complete(); 
      } 
     } 


    } 

    private List<string> GetDataStringInBatches(StringBuilder dataStringToProcess) 
    { 

     List<string> batchDataStringList = new List<string>(); 
     int loopCounter = 0; 
     string currentBatchString = string.Empty; 
     int numberOfRecordsinBacth = 5000; 
     int sizeOfTheBatch = 0; 

     List<string> individualEntriesList = new List<string>(); 
     string dataString = string.Empty; 
     if (dataStringToProcess != null) 
     { 
      dataString = dataStringToProcess.ToString(); 
     } 
     individualEntriesList.AddRange(dataString.Split(new char[] { '|' })); 


     for (loopCounter = 0; loopCounter < individualEntriesList.Count; loopCounter++) 
     { 

      if (String.IsNullOrEmpty(currentBatchString)) 
      { 
       currentBatchString = System.Convert.ToString(individualEntriesList[loopCounter]); 
      } 
      else 
      { 
       currentBatchString = currentBatchString+"|"+System.Convert.ToString(individualEntriesList[loopCounter]); 
      } 

      sizeOfTheBatch = sizeOfTheBatch + 1; 
      if (sizeOfTheBatch == numberOfRecordsinBacth) 
      { 
       batchDataStringList.Add(currentBatchString); 
       sizeOfTheBatch = 0; 
       currentBatchString = String.Empty; 
      } 


     } 

     return batchDataStringList; 


    } 

    private void PerformDatabaseOperation(string dataStringToProcess, int UserID) 
    { 
     SqlConnection mySqlConnection = new SqlConnection("data source=myServer;initial catalog=myDB; Integrated Security=SSPI; Connection Timeout=0"); 
     SqlCommand mySqlCommand = new SqlCommand("aspInsertUSAZipCode", mySqlConnection); 
     mySqlCommand.CommandType = CommandType.StoredProcedure; 
     mySqlCommand.Parameters.Add("@DataRows", dataStringToProcess.ToString()); 
     mySqlCommand.Parameters.Add("@currDate", DateTime.Now); 
     mySqlCommand.Parameters.Add("@userID", UserID); 
     mySqlCommand.Parameters.Add("@CountOfUnchangedZipCode", 1000); 
     mySqlCommand.CommandTimeout = 0; 
     mySqlConnection.Open(); 
     int numberOfRows = mySqlCommand.ExecuteNonQuery(); 
    } 

開發ENV:視覺Studion 2005

框架:NET 3.0

DB:SQL Server 2005中

當我運行查詢SELECT [尺寸],MAX_SIZE,Data_Space_Id,[ File_Id],Type_Desc,[Name] FROM MyDB.sys.database_files WHERE data_space_id = 0 - 它表示(日誌)的大小爲128

UPDATE 我們在應用程序中使用了三種不同的數據庫。一個用於數據,一個用於歷史記錄,另一個用於記錄。當我把enlist = false放在上面的連接字符串中時,它現在正在工作。但它在我的開發環境中。我懷疑它是否也能用於生產。任何關於潛在風險的想法?

感謝

Lijo

回答

1

aspInsertUSAZipCode是否有可能與鏈接的服務器進行交互?如果確實如此,那麼它會嘗試將當前本地事務提升爲分佈式事務(在您的服務器和鏈接服務器之間保留事務完整性)。

如果遠程服務器上的MSDTC無法配置爲分佈式事務,則可能需要在事務外執行此操作。我認爲最好的方法是創建一個臨時表,然後將您的記錄添加到SqlBulkCopy中,然後使用服務器上的臨時表執行aspInsertUSAZipCode。您可能需要使用遊標。

臨時表的目的是,如果出現問題,在連接終止時刪除表。

+0

實際要求是:在zipcode表中有一些現有的zipcode。管理員每個月都會上傳新的zipcode csv文件。插入來自csv的新項目。在csv中不可用的郵政編碼(但存在於數據庫中)被認爲是退役並將被刪除。已退役的郵政編碼列表將被退回到用戶界面。新增加的郵政編碼也需要退回。 使用SqlBulkCopy可以實現這個功能嗎?你可以請參考一個很好的例子嗎? – Lijo

+0

我們在應用程序中使用了三種不同的數據庫。一個用於數據,一個用於歷史記錄,另一個用於記錄。 當我將enlist = false放入連接字符串中時,它暫時工作。但它在我的開發環境中。我懷疑它是否也能用於生產。任何關於潛在風險的想法? – Lijo

+1

如果您正在跨數據庫進行事務處理,那麼您正在執行分佈式事務。如果數據庫位於不同的機器上,並且您希望在事務內完成這項工作,則需要爲遠程事務配置MSDTC。或者,您自己的應用程序可以建立三個連接(每個數據庫一個連接)。在這種情況下,您將通過應用程序在數據庫之間傳遞數據並管理三種不同的事務。配置MSDTC有這樣的問題嗎? –

0

你可能創下一個交易限額數據的一些最大金額。

檢查事件日誌中的任何錯誤,MSDTC http://technet.microsoft.com/en-us/library/cc774415(WS.10).aspx

有在一個事務100,000行是要給你的問題。

我不認爲在這種情況下單個事務將會起作用,您需要查看您在此處使用事務的原因,並找到完成該事務的不同方式。

+0

我們在我們的應用程序中使用了三種不同的數據庫。一個用於數據,一個用於歷史記錄,另一個用於記錄。當我把enlist = false放在上面的連接字符串中時,它現在正在工作。但它在我的開發環境中。我懷疑它是否也能用於生產。任何關於潛在風險的想法? – Lijo

+0

我認爲單個事務中的100,000行不會接近SQL Server的任何限制來維護事務完整性。可能有100,000個報表。 –

+0

它正在Performdatabase操作中打開一個新的sql連接,並且沒有緊密連接 –

6

當您在TransactionScope中打開多個連接時,正在運行的事務將自動升級爲分佈式事務。爲使分佈式事務正常工作,SQL Server和運行該應用程序的計算機上的MSDTC必須配置爲允許網絡訪問。運行分佈式事務時,SQL Server和本地DTC通信。

你的情況的問題很可能是運行應用程序的機器上的MSDTC不允許網絡訪問,因爲這是工作站的默認設置。要解決此問題,請執行以下操作:

  1. 轉到「控制面板」 - >「管理」 - >「組件服務」。
  2. 瀏覽樹狀圖,直到找到名爲「本地DTC」或類似的節點。
  3. 右鍵單擊並選擇「屬性」。
  4. 轉到「安全」,並確保允許網絡訪問,並允許與DTC進行入站和出站通信。
  5. 點擊「確定」。

您可能會被提示重新啓動DTC。在UI中似乎存在一個錯誤,因爲即使您接受DTC的重新啓動,它也不會重新啓動。相反,您必須在服務管理器中手動重新啓動DTC服務。

順便說一句,記得在PerformDatabaseOperation使用後關閉連接。將它放在一個using塊中是一種很好的做法:

using (SqlConnection mySqlConnection = new .....) 
{ 
    // Some code here... 
    mySqlConnection.Open(); 
    // Some more code ... 
} 
+0

非常感謝,這解決了它對我來說 – Thousand

+0

謝謝[Jackob](http://stackoverflow.com/users/64161/jakob-christensen)。 –