2012-10-23 44 views
1

我有N進程運行SQL Server 2008.如果任何進程失敗,我需要回滾所有其他人。使用事務與任務並行庫

我正在考慮使用TPL創建父任務和N子任務。所有這些都包含在transactionScope(IsolationLevel.ReadCommitted)中,但在我的示例中,child2將引發錯誤(customers2不是有效表),並且child1不會回滾。

我在這裏假設有問題嗎?有沒有其他方式來管理這種情況?

這裏是我的測試代碼:

編輯 我修改了代碼,如下使用DependClone當前事務。我認爲正在工作。

try 
     { 
      using (TransactionScope mainTransaction = TransactionUtils.CreateTransactionScope()) 
      { 
       var parentTransactionClone1 = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete); 
       var parentTransactionClone2 = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete); 

       var parentTask = Task.Factory.StartNew(() => 
       { 
        var childTask1 = Task.Factory.StartNew(() => 
        { 
         using (TransactionScope childScope1 = new TransactionScope(parentTransactionClone1)) 
         { 
          SqlConnection cnn = new SqlConnection("Server=.\\sqlexpress;Database=northwind;Trusted_Connection=True;"); 
          cnn.Open(); 
          SqlCommand cmd = new SqlCommand("update customers set city ='valXXX' where customerID= 'ALFKI'", cnn); 
          cmd.ExecuteNonQuery(); 
          cnn.Close(); 
          childScope1.Complete(); 
         } 

         parentTransactionClone1.Complete(); 

        }, TaskCreationOptions.AttachedToParent); 

        var childTask2 = Task.Factory.StartNew(() => 
        { 
         using (TransactionScope childScope2 = new TransactionScope(parentTransactionClone2)) 
         { 
          SqlConnection cnn = new SqlConnection("Server=.\\sqlexpress;Database=northwind;Trusted_Connection=True;"); 
          cnn.Open(); 
          SqlCommand cmd = new SqlCommand("update customers2 set city ='valyyy' where customerID= 'ANATR'", cnn); 
          cmd.ExecuteNonQuery(); 
          cnn.Close(); 

          childScope2.Complete(); 
         } 

         parentTransactionClone2.Complete(); 

        }, TaskCreationOptions.AttachedToParent); 
       }); 

       parentTask.Wait(); 
       mainTransaction.Complete(); 
      } 
     } 
     catch (Exception ex) 
     { 
      // manage ex    
     } 
public static TransactionScope CreateTransactionScope() 
    { 
     var transactionOptions = new TransactionOptions(); 
     transactionOptions.IsolationLevel = IsolationLevel.ReadCommitted; 
     transactionOptions.Timeout = TransactionManager.MaximumTimeout;    
     return new TransactionScope(TransactionScopeOption.Required, transactionOptions); 
    } 
+0

對於這種情況,似乎你可以創建一個SqlTransaction並在兩個SqlCommand中使用它? –

回答

4

TransactionScope類爲當前線程的環境交易(另見Transaction.Current只。

你至少應該假設每個任務在一個單獨的線程中運行(儘管這是不是與TPL的必需品)。

審查「重要」框中的the relevant article備註部分 - 如果你想分享的線程之間的交易,你需​​要使用DependentTransaction類

就個人而言,我相信整個設施共享多個線程之間的事務在技​​術上工作,但是,我總是發現寫一個使用每個線程單獨事務的設計更容易。

0

任務並行庫無法弄清楚自身任務的細節,它不會自動回滾,你可以做的最接近的是從你定義的另一個任務child1回滾父任務只有在child1失敗的情況下才會執行,並且您可以通過將TaskContinuationOption設置爲OnlyOnFailure來很好地定義它,因此只有在child1失敗時纔會執行該任務,對child2也可以這樣說。