2014-03-28 94 views
1

我想在C#中首次使用嵌套事務。在過去,我總是將包裹在SqlTransactions裏面SqlConnections。事情是這樣的:嵌套的TransactionScope()將不會回滾

using (SqlConnection myCon = new SqlConnection(...))  
    using (SqlTransaction myTran = myCon.BeginTransaction()) 
    { 
     using (SqlCommand myCom1 = new SqlCommand("...", myCon, myTran)) 
     { 
      ... 
     }  
     using (SqlCommand myCom2 = new SqlCommand("...", myCon, myTran)) 
     { 
      ... 
     } 
     . 
     . 
     . 
     myTran.Commit(); 
    } 
} 

所有這一切,必要try...catch處理過程的,所以如果一個異常SqlTransaction內的任何地方發生,我知道沒有SqlCommands的將被提交。

所以我想我會給TransactionScope一個嘗試,但它不工作。這是我正在做的事情;我有兩個交易,一個接一個,但都在一個外部交易中。根據表單上選中哪個複選框,代碼將引發以下異常: 1.恰好在第一個內部事務的提交之前,或者 2.在兩個內部事務之間,或者 3.就在第二個內部事務的提交之前,或 4.就在外部交易提交之前

我得到的問題是,無論我勾選哪個複選框,代碼都會執行,就好像沒有交易存在一樣。換句話說,由於異常導致跳出try塊的事實不會回滾任何事務。

希望得到一些幫助。以下是我的小測試應用程序的代碼。

try 
{ 
    using (SqlConnection sqlConnection = new SqlConnection(connectionString)) 
    { 
     sqlConnection.Open(); 

     using (TransactionScope transactionOuter = new TransactionScope()) 
     { 
      using (TransactionScope transactionInner1 = new TransactionScope()) 
      { 
       using (SqlCommand sqlCommand = new SqlCommand("INSERT INTO BasicTable (Value) VALUES ('Inside Inner Transaction 1')", sqlConnection)) 
       { 
        sqlCommand.ExecuteNonQuery(); 
       } 

       if (checkBox_FailInner1.Checked) 
        throw (new Exception("Failed inside inner transaction 1")); 

       transactionInner1.Complete(); 
      } 

      if (checkBox_FailBetween.Checked) 
       throw (new Exception("Failed between inner transactions")); 

      using (TransactionScope transactionInner2 = new TransactionScope()) 
      { 
       using (SqlCommand sqlCommand = new SqlCommand("INSERT INTO BasicTable (Value) VALUES ('Inside Inner Transaction 2')", sqlConnection)) 
       { 
        sqlCommand.ExecuteNonQuery(); 
       } 

       if (checkBox_FailInnner2.Checked) 
        throw (new Exception("Failed inside inner transaction 2")); 

       transactionInner2.Complete(); 
      } 

      if (checkBox_FailOuter.Checked) 
       throw (new Exception("Failed before outer transaction could commit")); 

      transactionOuter.Complete(); 
     } 
    } 
} 
catch (Exception exc) 
{ 
    MessageBox.Show(exc.Message); 
} 

MessageBox.Show("Done"); 
+0

那麼,你有哪些例外? –

+0

我沒有得到任何異常,或者至少沒有任何異常,我沒有投擲自己。關鍵是,我期待這一點,當我在我所做的四點中的任何一點處拋出異常時,最終應導致外部事務回滾,因此沒有任何SQL命令應該對數據庫進行永久更改。這沒有發生。無論我在哪裏拋出異常,上述示例中的事務都不會回滾。 –

回答

2

A SqlConnection當它打開時會自己登記。只有這個時間點是重要的。該連接將被列入當時正在進行的任何交易。您正在安裝任何事務之前打開連接。

我相信你有第二個誤解:它不可能嵌套交易。您只能嵌套範圍。當您回滾內部作用域時,整個事務將回滾。所有TransactionScope確實設置和操縱Transaction.Current。而已。最外面的作用域將安裝一個事務。內部作用域大多是沒有作用的。他們所做的一切都是通過不完成這些交易來提供一種交易方式。

+1

啊哈!謝謝。所以看起來嵌套順序應該是TransactionScope - > SqlConnection - > SqlCommand,而不是SqlConnection - > TransactionScope - > SqlCommand?這與我習慣的約定(SqlConnection - > SqlTransaction - > SqlCommand)不同。 –

+1

是的,正確的。閱讀有關SO上的交易範圍的重要問題以查看(衆多)陷阱是什麼可能是一個好主意。 – usr