2013-03-08 168 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