SQLTransaction已完成错误

时间:2013-03-08 12:07:41

标签: c# .net ado.net transactionscope

我在申请中遇到了一次错误。

  

此SQLTransaction已完成;它不再可用了

下面附有堆栈跟踪 - 它说明了Zombie CheckRollback

代码中的错误是什么?

注意:此错误只出现一次。

更新

来自MSDN - SqlTransaction.Rollback Method

  

如果连接已终止或者事务已在服务器上回滚,则Rollback会生成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

5 个答案:

答案 0 :(得分:7)

  

注意:此错误只出现一次。

然后很难说出来;可能只是// Other Code等只是花了很长时间,整个事情都被杀死了。也许你的连接已经死亡,或者管理员故意将其杀死,因为你正在阻止它。

  

代码中的错误是什么?

过度复杂化;它可以更简单:

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;
         }
    }
}

更少的代码出错。

答案 1 :(得分:6)

你应该把一些工作留给编译器,把它包装在try / catch / 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

  

如果连接已终止或者事务已在服务器上回滚,则Rollback会生成InvalidOperationException。

重新抛出一个新例外,告诉用户数据可能尚未保存,并请她刷新并查看

答案 2 :(得分:2)

我使用下面的代码可以重现此错误,我使用1000个任务来执行Sql,在大约300个任务成功完成后,timeout error开始出现很多关于ExecuteNonQuery()的例外,

然后在This SqlTransaction has completed上发生下一个错误transaction.RollBack();,其调用堆栈也包含ZombieCheck()

(如果1000个任务的单个程序压力不够,可以同时执行多个编译的exe文件,甚至可以使用多台计算机执行一个数据库。)

所以我猜其中一个导致此错误的原因可能是Connection出错了,导致事务错误也会发生。

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);

            }
        }
    }
}

此外,我发现如果我提交两次sequentail也会调用此异常。

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

或者,如果在提交之前Connection Connection也调用此错误。

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

<强>更新

我觉得很奇怪,我创建了另一个新表并向其插入了50万个数据,

然后使用select * from newtable sql执行100000个任务,同时运行5个程序,这次发生超时错误,但是transaction.Rollback()时它没有调用SQLTransaction has completed error。< / p>

但如果发生超时错误,请跳转到catch块,然后在catch块再次执行transaction.Commit()SQLTransaction has completed error将会发生。

答案 3 :(得分:1)

我曾经历过这个错误,我被困住了,无法知道出了什么问题。实际上我正在删除一条记录,在存储过程中,我没有删除它的孩子,特别是Stored Procedure中的删除语句在Transaction边界内。我从存储过程中删除了该事务代码,并且摆脱了“This SqlTransaction has completed; it is no longer usable.”

的错误

答案 4 :(得分:0)

这条消息只是因为您编写的代码在事务已成功提交后抛出异常。请尝试检查您在Commit方法后编写的代码或您可以使用Try..Catch处理它,最后使用Blocks :)。