2012-11-26 57 views
2

我正在嘗試使用System.Transactions(TransactionScope)來協調一組進程,每個進程都執行一些數據庫工作。最終,所有進程都需要通過一個父進程進行原子級回滾或回滾。不幸的是,迄今爲止我沒有嘗試過。跨進程使用事務

我的基本策略是在父進程中將TransactionScope保存到文件中,然後調用加載文件的子進程,在自己的TransactionScope中使用事務並返回到父進程。

但這不適用於我。當我從調用第一個孩子回來時,我有時會看到父交易已被標記爲中止。試圖克隆它然後拋出TransactionAbortedException。

當第二個孩子試圖反序列化事務時,我也看到異常,我得到一個TransactionException代碼0x8004d00e。

我想要做的是TransactionScope across AppDomains and processeshttp://blogs.microsoft.co.il/blogs/sasha/archive/2010/04/30/propagating-a-transaction-across-appdomains.aspx中描述的內容。無論如何,沒有運氣。

這裏有一些事情我都試過了,沒有成功:

  1. 從加載交易
  2. 創建通過DependentClone父進程DependentTransaction()創建通過DependentClone子進程中的一個DependentTransaction() ,節省了 交易文件
  3. 創建克隆()在父進程,節省了 交易文件
  4. 保存我們在交易前前荷蘭國際集團系列化
  5. 保存使用 TransactionInterop.GetTransactionFromTransmitterPropagationToken()交易
  6. 明確地打開父母的 的TransactionScope前連接
  7. 明確爭取母公司內部交易
  8. 明確爭取孩子裏面的交易
  9. 完成/未完成父母的範圍
  10. 完成/未完成對子女的範圍

明確創建CommittableTransaction這裏有一個例外消息:

System.Transactions.TransactionException:該事務已或隱式地提交或中止。 ---> System.Runtime.InteropServices.COMException:該事務已或隱式地提交或(從HRESULT異常:0x8004D00E)中止

,而其他(使用DependentClone時()):

系統.Transactions.TransactionAbortedException:事務已中止。 at System.Transactions.TransactionStatePromotedAborted.CreateBlockingClone( ternalTransaction tx) at System.Transactions.DependentTransaction ..構造函數(ISOLEVEL的IsolationLevel,在 ternalTransaction internalTransaction,布爾阻塞) 在System.Transactions.Transaction.DependentClone(DependentCloneOption cloneO ption)

任何想法我做錯了嗎?我已經嘗試了很多這個沒有任何運氣的排列組合。

下面是一些代碼(不試圖證明上述所有變體):

 // one variant I have tried is to create a CommittableTransaction 
     // and pass that in the scope below 

     using (TransactionScope scope = new TransactionScope()) 
     { 
      // optionally, do some parent-level EF work 

      // invoke child operations in other processes 
      DoChildOperation_OutOfProc(1, Transaction.Current); 
      DoChildOperation_OutOfProc(2, Transaction.Current); 

      scope.Complete(); 
     } 

     // in the variant where I created a CommittableTransaction, 
     // I committed it here 

    ... 

    private static void DoChildOperation_OutOfProc(int id, Transaction transaction) 
    { 
     string tranFile = string.Format("ChildTran_{0}.txt", id); 
     SaveTransactionToFile(transaction, tranFile); 

     Process process = new Process(); 
     process.StartInfo = new ProcessStartInfo(Process.GetCurrentProcess().MainModule.FileName.Replace(".vshost", string.Empty), 
      string.Format("-CHILDID={0} -TRANFILE={1}", id, tranFile)); 
     process.StartInfo.UseShellExecute = false; 
     process.Start(); 
     process.WaitForExit(); 
    } 

    private static void SaveTransactionToFile(Transaction transaction, string tranFile) 
    { 
     byte[] transactionBytes = 
      TransactionInterop.GetTransmitterPropagationToken(transaction); 

     string tranFileContents = Convert.ToBase64String(transactionBytes); 

     File.WriteAllText(tranFile, tranFileContents); 
    } 

    private static Transaction LoadTransactionFromFile(string tranFile) 
    { 
     string tranFileContents = File.ReadAllText(tranFile); 
     File.Delete(tranFile); 

     byte[] tranBytes = Convert.FromBase64String(tranFileContents); 

     Transaction tran = 
      TransactionInterop.GetTransactionFromTransmitterPropagationToken(tranBytes); 
     return tran; 
    } 

    // the child instance of the app runs this after decoding the arguments 
    // from DoChildOperation_OutOfProc() and loading the transaction out of the file 

    private static void DoChildOperation(int id, Transaction childTransaction) 
    { 
     // in one variant, I call 
     // childTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete) 
     // and then use that inside the TransactionScope 

     using (TransactionScope scope = new TransactionScope(childTransaction)) 
     { 
      // do EF work and call SaveChanges() 

      scope.Complete(); 
     } 

     // if I created a dependent clone, call Complete() here on it 
+1

這真的很好,你已經解釋了你遇到的問題/錯誤..但是你能否顯示完整的代碼塊正在執行事務代碼..? – MethodMan

+0

我已經添加了一些代碼,有點消毒,但希望它更清楚。 – Todd

+0

這看起來很毛茸茸。任何原因你不能將工作分成多個交易,並在必要時使用補償來回滾> –

回答

0

好,關鍵似乎是,你可以在父使用的TransactionScope,但不是在兒童。對於孩子,我打開EF連接,使用傳遞的事務調用connection.EnlistTransaction(),並執行EF SaveChanges()或transaction.Rollback()但不提交(Transaction類不提供此功能)。這樣做,看起來我得到了期望的行爲。

我理解中的差距實際上是否事務是嵌套的(就像你可以在SQL Server中那樣)。看起來它確實不是;這是同一個交易。注意:即使您在子級中使用Transaction.DependentClone()創建DependentTransaction,如果將其放入TransactionScope中,仍然會失敗。

這證明是有點不幸,因爲這意味着如果你的進程是父進程,你可以使用TransactionScope,但如果它是一個孩子,你不能。