2013-03-08 852 views
10

我在應用程序中遇到過一次錯誤。SQLTransaction已完成錯誤

此SQLTransaction已完成;它不再可用

堆棧跟蹤如下連接 - 它說,大約Zombie CheckRollback

代碼中的錯誤是什麼?

注意:此錯誤只出現一次。

UPDATE

MSDN - SqlTransaction.Rollback Method

如果連接被終止,或者如果該事務已經被回滾服務器上的回滾生成一個InvalidOperationException。

Zombie check on Transaction - Error

一個我看到這個錯誤出在各種應用了最常見的原因是,共享跨我們的應用程序的SqlConnection。

CODE

public int SaveUserLogOnInfo(int empID) 
{ 
     int? sessionID = null; 
     using (SqlConnection connection = new SqlConnection(connectionString)) 
     { 
      connection.Open(); 
      SqlTransaction transaction = null; 
      try 
      { 
       transaction = connection.BeginTransaction(); 
       sessionID = GetSessionIDForAssociate(connection, empID, transaction); 

        //Other Code 

       //Commit 
       transaction.Commit(); 
      } 
      catch 
      { 
       //Rollback 
       if (transaction != null) 
       { 
        transaction.Rollback(); 
        transaction.Dispose(); 
        transaction = null; 
       } 

       //Throw exception 
       throw; 
      } 
      finally 
      { 
       if (transaction != null) 
       { 
        transaction.Dispose(); 
       } 
      } 
     } 

     return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture); 

    } 

堆棧跟蹤

enter image description here


參考

  1. What is zombie transaction?
  2. Zombie check on Transaction - Error
  3. SqlTransaction has completed
  4. http://forums.asp.net/t/1579684.aspx/1
  5. "This SqlTransaction has completed; it is no longer usable."... configuration error?
  6. dotnet.sys-con.com - SqlClient Connection Pooling Exposed
  7. Thread abort leaves zombie transactions and broken SqlConnection

+1

什麼是導致您的代碼達到'catch'的異常? – Maarten 2013-03-08 12:13:09

+1

在這種情況下,您應該爲您的交易使用「使用」聲明。請參閱http://stackoverflow.com/questions/1127830/why-use-a-using-statement-with-a-sqltransaction – Maarten 2013-03-08 12:14:07

+1

@Maarten公平,OP *確保*確保它被丟棄;但我同意*不*使用'使用'使得它過於複雜 – 2013-03-08 12:15:13

回答

5

您應該將一些工作留給編譯器,以便將它包裝在try//finally中。

此外,你應該預料到Rollback偶爾會拋出一個異常,如果Commit階段出現問題,或者如果服務器斷開連接。出於這個原因,你應該把它包裝在try/catch

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. 
    Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType()); 
    Console.WriteLine(" Message: {0}", ex2.Message); 
} 

這完全是從MSDN documentation page for Rollback method複製的。

我看到你擔心你有殭屍交易。如果你粘貼,這聽起來不像你有問題。你的交易已經完成,你不應該再與它有任何關係。如果你拿着它們,請刪除它的引用,並忘記它。


MSDN - SqlTransaction.Rollback Method

回滾如果連接被終止,或者如果該事務已經被回滾在服務器上生成一個InvalidOperationException。

重新拋出一個新的異常,告訴用戶該數據可能還沒有被保存,並問她刷新和審查

+0

如果我吞下異常,代碼分析中會出現嚴重警告。這意味着如果我不'拋出'catch'異常。 – Lijo 2013-03-08 12:20:26

+0

然後,您的分析政策出現問題。我不相信你不允許實際處理異常?你把所有的例外都拋給用戶嗎? – 2013-03-08 12:21:40

+0

是的,我需要記錄異常並將其扔到前端。我通常在客戶端應用程序中拋出自定義異常。 – Lijo 2013-03-08 12:23:13

6

注意:此錯誤只出現一次。

那麼很難說很多;它可能只是簡單地花了很長時間,整個事情都被殺死了。也許你的聯繫死了,或者管理員故意殺死它,因爲你被阻止了。

代碼中的錯誤是什麼?

過度複雜化它;它可以更簡單:

using (var connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 
    using(var transaction = connection.BeginTransaction()) 
    { 
     try 
     { 
      sessionID = GetSessionIDForAssociate(connection, empID, transaction); 
      //Other Code 
      transaction.Commit(); 
     } 
     catch 
     { 
      transaction.Rollback(); 
      throw; 
     } 
    } 
} 

更少的代碼出錯。

+3

在你的情況下,你可以保存更多的行,如果你刪除try catch ..使用「using」語句,一個事務會自動回滾,如果有異常happenes ..見http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.aspx – nWorx 2013-03-08 12:24:19

+0

謝謝。但我不明白爲什麼建議的代碼可以解決問題。是因爲你沒有調用Dispose()? – Lijo 2013-03-08 12:30:29

+0

@nWorx更好 – 2013-03-08 12:37:22

0

此消息完全是因爲你寫拋出異常的代碼事務具有後已成功提交。請嘗試檢查您在Commit方法或之後編寫的代碼,您可以使用Try..Catch最後處理塊 :)。

1

我曾經遇到過這個錯誤,我被卡住了,無法知道發生了什麼問題。實際上,我刪除了一條記錄,而在存儲過程中,我並沒有刪除它的孩子,特別是Stored Procedure中的刪除語句位於Transaction邊界內。我刪除了交易碼存儲過程,並擺脫得到的「This SqlTransaction has completed; it is no longer usable.」

1

這個錯誤我用下面的代碼可以重現這個錯誤,我用1000級的任務來執行SQL後,在約300任務的順利完成,很多例外的約timeout error開始發生在ExecuteNonQuery()

然後下一個錯誤This SqlTransaction has completed將發生在transaction.RollBack();及其調用棧還包含ZombieCheck()。 (如果單個程序有1000個任務壓力不夠,可以同時執行多個編譯的exe文件,甚至可以使用多臺計算機執行到一個DataBase。)

所以我猜想導致此錯誤的原因之一可能是連接中的錯誤,然後導致交易錯誤也發生。

Task[] tasks = new Task[1000]; 
for (int i = 0; i < 1000; i++) 
{ 
    int j = i; 
    tasks[i] = new Task(() => 
     ExecuteSqlTransaction("YourConnectionString", j) 
     ); 
} 

foreach (Task task in tasks) 
{ 
    task.Start(); 
}  

/////////////  

public void ExecuteSqlTransaction(string connectionString, int exeSqlCou) 
{ 

    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     connection.Open(); 

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

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

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

     try 
     { 
      command.CommandText = 
       "select * from Employee"; 
      command.ExecuteNonQuery(); 

      // Attempt to commit the transaction. 
      transaction.Commit(); 

      Console.WriteLine("Execute Sql to database." 
       + exeSqlCou); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Commit Exception Type: {0}", ex.GetType()); 
      Console.WriteLine(" Message: {0}", ex.Message); 


      // 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. 
       Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType()); 
       Console.WriteLine(" Message: {0}", ex2.Message); 

      } 
     } 
    } 
} 

此外我發現如果我提交兩次sequentailly也會調用此異常。

 transaction.Commit(); 
     transaction.Commit(); 

或者如果連接在提交之前關閉也會調用此錯誤。

 connection.Close(); 
     transaction.Commit(); 

更新:

我覺得奇怪的是我創建另一個新表,並插入50萬個數據,那麼,

然後用10萬級的任務與select * from newtable SQL,運行5個程序在同時,此時會發生超時錯誤,但當transaction.Rollback()未啓用SQLTransaction has completed error時。

但是,如果發生超時錯誤,跳入catch塊,並在catch塊中再次執行transaction.Commit(),將發生SQLTransaction has completed error

相關問題