2011-12-11 18 views
4

我有多個客戶端通過不可靠(無線/ gprs)網絡連接到SQL Server,並在幾分鐘內執行大量小型查詢並插入。如果在此過程中網絡連接中斷,整個事務將回滾並需要重新啓動。由於業務需求,流程必須是事務性的(即其他客戶端可以看到來自其他客戶端的完整數據集或根本看不到它)。在IP更改後重新連接丟棄的SqlConnection而不回滾事務

我希望能夠檢測到連接中斷並能夠重新連接到SQL Server,並在剛剛被刪除的同一個事務中繼續處理,並避免從頭開始重新啓動。在我使用sp_getbindtoken打開連接之後的那一刻,設置CommandTimeout小的值(比TCP保持活動小很多),如果我在ExecuteNonQuery得到超時,我打開服務器新的連接和呼叫sp_bindsession從過程的開始標誌。然後我繼續使用綁定到前一個進程事務的會話的新連接進程。

到目前爲止,這是工作幾乎完全,但根據MSDN,這個API已被棄用,並且將在SQL Server的未來版本中刪除。問題是:如果沒有這兩個命令,我怎麼能達到相同的結果?是否有任何其他方式從丟棄的TCP連接恢復事務?

編輯/更多信息:客戶端應用程序在帶有條形碼掃描儀的Windows CE設備上運行。我提供設備和軟件,所以我可以隨意放置任何我需要的東西。 DB由第三方託管在受保護的環境中,我和客戶都無法控制它。我總共發送約50MB的日常銷售數據。我可以使用SP來保存數據,但它仍然需要傳輸,並且有一個大參數的SP對GPRS/EDGE鏈路的成功機率可能接近0%。

由於整個解決方案在生產環境中工作,我希望保持更改爲最小。與sp_bindsession具有相同語義的替代API將是完美的。

+0

您是否考慮過製作客戶端服務器應用程序,以便TSQL發生在硬連接到SQL服務器(或與SQL服務器相同的設備)的服務器上? – Paparazzi

+0

@BalamBalam:是的,我創建了自己的實現IDbConnection的類,並將所有方法調用(緩衝)轉發給定製服務器,並在SqlConnection上調用適當的方法。隧道是使用.NET Remoting通道完成的,並且足夠強大。不幸的是,現在應用程序部署在我無法在DB服務器上或附近放置自定義代碼的環境中,所以我不得不使用純粹的TSQL解決方案。 – MagnatLU

+0

多個無線客戶端上的自定義代碼正常,但單個有線框上的自定義代碼不正常。這是一種奇怪的安全邏輯。邏輯或不是這聽起來像一個硬性約束。由於交易被設計爲回滾到開始,所以這至少會有問題。你真的在客戶端的.net上運行交易嗎?您可以將事務移動到服務器上的存儲過程嗎? – Paparazzi

回答

0

您提供的MSDN鏈接建議使用MARS。根據文章:

MARS允許連接用於具有多個掛起操作的讀取操作和數據操作語言(DML)操作。此功能消除了應用程序處理連接忙錯誤的需要。另外,MARS可以代替通常消耗更多資源的服務器端遊標的用戶。最後,因爲多個操作可以在單個連接上運行,所以它們可以共享相同的事務上下文,從而無需使用sp_getbindtoken和sp_bindsession系統存儲過程。

這樣你可以使用BeginTrasaction,事務會自動回滾,除非你明確地提交它。您可以捕獲commit語句的失敗,並遞歸地嘗試重新提交它,直到事務提交成功返回。只是一個想法。也許這樣的事:

private static void ExecuteSqlTransaction(string connectionString) 
{ 
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     connection.Open(); 

     SqlCommand command = connection.CreateCommand(); 
     SqlTransaction transaction; 

     // Start a local transaction. 
     transaction = connection.BeginTransaction("SampleTransaction"); 

     // Must assign both transaction object and connection 
     // to Command object for a pending local transaction 
     command.Connection = connection; 
     command.Transaction = transaction; 

     try 
     { 
      command.CommandText = 
       "Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')"; 
      command.ExecuteNonQuery(); 
      command.CommandText = 
       "Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')"; 
      command.ExecuteNonQuery(); 

      // Attempt to commit the transaction. 
      transaction.Commit(); 
      //Both records are written to database. 
     } 
     catch (Exception ex) 
     { 
      // Attempt to roll back the transaction. 
      try 
      { 
       transaction.Rollback(); 
      } 
      catch (Exception ex2) 
      { 
       // This catch block will handle any errors that may have occurred 
       // on the server that would cause the rollback to fail, such as 
       // a closed connection. 
       ExecuteSqlTransaction(connectionString); 
      } 
     } 
    } 
} 
+0

我想你誤解了我的問題。失敗不僅可能發生在提交上,而且可能發生在其他每個語句上。例如。如果有三次調用「ExecuteNonQuery」,第二次調用失敗,我想繼續執行第二次調用 - 你建議從第一條語句重新開始。 – MagnatLU

2

我只是不買那個〜50MB的日常銷售數據需要在一個單一的交易。我購買的個人銷售交易需要在sql-transaction中進行包裝,但這些交易將更像每個1K。您確定無法在存儲過程中在服務器上運行幾個小事務嗎?如果它必須是每個設備的全部或全部沒有,則通過小事務將設備加載到登臺表。設備完成後,在事務中使用服務器上的存儲過程來刷新登臺表。或者只需在上傳完成時放置一個布爾列,然後在上載完成時單次更新該標誌。一個50MB的交易確實會敲擊交易日誌並鎖定其他更新。

+0

「銷售數據」包括付款計劃,詳細信息,協議,附件和文檔掃描 - 每天通常超過50MB,並且使用「讀取承諾快照」隔離,無論您是否購買它都工作得很好。在小型交易中即時發送數據是可行的,但不是在系統部署時。重寫應用程序的內核不會很快得到批准。我詢問過時的API,而不是設計提示,因爲我堅持使用它。不過,感謝您的反饋。如果在下一版SQL Server中刪除'sp_bindsession',我將選擇登臺表。 – MagnatLU

+0

我不懷疑它是一天50MB。我懷疑這是一個交易。事務的目的是使多個表中的行級數據處於一致的狀態。你確定你不能把這50MB分解成多個原子事務嗎? – Paparazzi

+0

它可以被分解成更小的塊,但老實說,我正在尋找一個像「使用此SP代替」或「此API因爲(...)而被刪除」的答案,並且您將不得不更改您的應用程序「 。我同意交易並不意味着以這種方式使用,但我無權強制執行這段代碼中的更改,無論它有多糟糕。 – MagnatLU

相關問題