2008-12-04 79 views
9

以下是我的事務範圍源代碼的當前體系結構。第三個插入引發了一個.NET異常(不是SQL異常),它不回滾前兩個插入語句。我做錯了什麼?TransactionScope不回滾事務

編輯:我刪除了從insert2和insert3的try/catch。我還從insert1 try/catch中刪除了異常處理實用程序,並將「throw ex」。它仍然不會回滾事務。

編輯2:我在Insert3方法中添加了try/catch,並在catch語句中添加了「throw」。它仍然不會回滾事務。

UPDATE:根據我收到的反饋意見中,「提供SQLHelper」類使用SqlConnection對象建立與數據庫的連接,然後創建一個SqlCommand對象,設置CommandType屬性,以「StoredProcedure的」調用ExecuteNonQuery方法的SqlCommand。

我也沒有將Transaction Binding = Explicit Unbind添加到當前連接字符串。我會在下一次測試中補充說明。

public void InsertStuff() 
{ 
    try 
    { 
     using(TransactionScope ts = new TransactionScope()) 
     { 
      //perform insert 1 
      using(SqlHelper sh = new SqlHelper()) 
      { 
       SqlParameter[] sp = { /* create parameters for first insert */ }; 

       sh.Insert("MyInsert1", sp); 
      } 

      //perform insert 2 
      this.Insert2(); 

      //perform insert 3 - breaks here!!!!! 
      this.Insert3(); 

      ts.Complete();    
     } 
    } 
    catch(Exception ex) 
    { 
     throw ex; 
    } 
} 

public void Insert2() 
{ 
    //perform insert 2 
    using(SqlHelper sh = new SqlHelper()) 
    { 
     SqlParameter[] sp = { /* create parameters for second insert */ }; 

     sh.Insert("MyInsert2", sp); 
    } 
} 

public void Insert3() 
{ 
    //perform insert 3 
    using(SqlHelper sh = new SqlHelper()) 
    { 
     SqlParameter[] sp = { /*create parameters for third insert */ }; 

     sh.Insert("MyInsert3", sp); 
    } 
} 
+0

我不想質疑你的開發技能等,但你如何測試交易已經回滾?交易是否可以正常運行,但是您誤解了結果。也許其他事情正在發生,我們/你在咆哮着錯誤的樹? – 2008-12-04 23:26:43

+0

希望這有助於:http://stackoverflow.com/questions/28191333/error-in-ambient-transaction-doesnt-rollback-the-transaction/28258935#28258935 – 2015-09-06 04:02:56

回答

6

看起來你正在捕捉Insert3()中的異常,所以你的代碼在調用後繼續。如果你想讓它回滾,你需要讓異常冒泡到主例程中的try/catch塊,以便ts.Complete()語句永遠不會被調用。

+0

所以,我應該從插入2刪除try/catch語句和3? – 2008-12-04 00:51:36

+0

是的。或重新拋出異常或其他異常。 – tvanfosson 2008-12-04 00:56:51

+0

是的,你沒有處理這個異常,主叫方只是繼續......也......是他們在sqlHelper中聲明的任何事務?......我在一個地方提交一個問題,將其刪除。 – 2008-12-04 01:03:28

1

只有在不調用ts.complete的情況下退出using纔會發生隱式回滾。因爲您正在處理Insert3()中的異常,所以異常不會導致using語句退出。

要麼重新拋出異常或通知需要回滾調用者(讓改變Insert3()的簽名爲bool Insert3()?)

1

(基於編輯的版本不下嚥例外)

這些操作需要多長時間?如果它們中的任何一個很長時間運行,則有可能Transaction Binding錯誤功能已咬住您 - 即連接已分離。嘗試將Transaction Binding=Explicit Unbind添加到連接字符串。

23

我也遇到過類似的問題。我的問題發生是因爲在我的SqlCommands中使用的SqlConnection在TransactionScope創建之前已經打開,所以它從來沒有作爲事務入賬到TransactionScope中。

是否有可能SqlHelper類重複使用在您進入TransactionScope塊之前打開的SqlConnection實例?

0

我沒有看到你的幫助程序類,但事務範圍回滾如果你沒有調用完整的語句,即使你從.NET代碼中得到錯誤。我爲你複製了一個例子。您可能在調試時出錯。這個例子在你的.net代碼和類似的catch塊中有錯誤。

private static readonly string _connectionString = ConnectionString.GetDbConnection(); 

    private const string inserttStr = @"INSERT INTO dbo.testTable (col1) VALUES(@test);"; 

     /// <summary> 
     /// Execute command on DBMS. 
     /// </summary> 
     /// <param name="command">Command to execute.</param> 
     private void ExecuteNonQuery(IDbCommand command) 
     { 
      if (command == null) 
       throw new ArgumentNullException("Parameter 'command' can't be null!"); 

      using (IDbConnection connection = new SqlConnection(_connectionString)) 
      { 
       command.Connection = connection; 
       connection.Open(); 
       command.ExecuteNonQuery(); 
      } 
     } 

     public void FirstMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello1")); 


       ExecuteNonQuery(command); 

     } 

     public void SecondMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello2")); 


       ExecuteNonQuery(command); 

     } 

     public void ThirdMethodCauseNetException() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello3")); 


       ExecuteNonQuery(command); 
      int a = 0; 
      int b = 1/a; 

     } 

    public void MainWrap() 
    { 


     TransactionOptions tso = new TransactionOptions(); 
     tso.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; 
     //TransactionScopeOption.Required, tso 
     try 
     { 
      using (TransactionScope sc = new TransactionScope()) 
      { 
       FirstMethod(); 
       SecondMethod(); 
       ThirdMethodCauseNetException(); 
       sc.Complete(); 
      } 
     } 
     catch (Exception ex) 
     { 
      logger.ErrorException("eee ",ex); 

     } 
    } 

如果您想調試您的事務,您可以使用此腳本查看鎖定和等待狀態等。

SELECT 
request_session_id AS spid, 
CASE transaction_isolation_level 
WHEN 0 THEN 'Unspecified' 
WHEN 1 THEN 'ReadUncomitted' 
WHEN 2 THEN 'Readcomitted' 
WHEN 3 THEN 'Repeatable' 
WHEN 4 THEN 'Serializable' 
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL , 
resource_type AS restype, 
resource_database_id AS dbid, 
DB_NAME(resource_database_id) as DBNAME, 
resource_description AS res, 
resource_associated_entity_id AS resid, 
CASE 
when resource_type = 'OBJECT' then OBJECT_NAME(resource_associated_entity_id) 
ELSE 'N/A' 
END as ObjectName, 
request_mode AS mode, 
request_status AS status 
FROM sys.dm_tran_locks l 
left join sys.dm_exec_sessions s on l.request_session_id = s.session_id 
where resource_database_id = 24 
order by spid, restype, dbname; 

在調用異常方法之前,您將看到兩個方法調用的一個SPID。

two calls before exception

默認隔離級別是可序列化。 You can read more about locks and transactions here