【问题标题】:SQLTransaction has completed errorSQLTransaction 已完成错误
【发布时间】:2013-03-08 12:07:41
【问题描述】:

我在我的应用程序中遇到了一次以下错误。

此 SQLTransaction 已完成;已经不能用了

堆栈跟踪附在下面——它说的是Zombie CheckRollback

代码有什么错误?

注意:这个错误只出现过一次。

更新

来自MSDN - SqlTransaction.Rollback Method

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

来自Zombie check on Transaction - Error

我在各种应用程序中看到此错误的最常见原因之一是,在我们的应用程序中共享 SqlConnection。

代码

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

   }

堆栈跟踪


参考

  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

【问题讨论】:

  • 导致您的代码到达“catch”的异常是什么?
  • 在这种情况下,您应该为您的交易使用“使用”语句。见stackoverflow.com/questions/1127830/…
  • @Maarten 公平地说,OP 确实 确保它得到处理;但我同意 not 使用 using 会使其过于复杂

标签: c# .net ado.net transactionscope


【解决方案1】:

您应该将一些工作留给编译器,以便为您将其包装在 try/catch/finally 中。

此外,如果Commit 阶段出现问题或与服务器的连接中断,您应该期望Rollback 偶尔会抛出异常。出于这个原因,您应该将其包装在 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。

重新抛出一个新异常,告诉用户数据可能还没有保存,并要求她刷新和查看

【讨论】:

  • 如果我吞下异常,代码分析中会出现严重警告。这意味着如果我不 throw catch 异常。
  • 那么您的分析策略有问题。我不敢相信您不允许实际处理异常?你会向用户抛出所有异常吗?
  • 是的,我需要记录异常并把它扔到前端。我通常在客户端应用程序中抛出我的自定义异常。
  • 在这种情况下,重新抛出一个新的异常,告诉用户数据可能没有保存,并要求她刷新和查看。简而言之,无论您做什么,都可能发生此错误,您需要问的唯一问题是您是否以及如何将其呈现给用户。
【解决方案2】:

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

那么很难说太多;可能很简单,// 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;
         }
    }
}

出错的代码要少得多。

【讨论】:

  • 在您的情况下,您可以节省更多行,如果您删除 try catch.. 使用“using”语句,如果发生异常,事务会自动回滚.. 参见 msdn.microsoft.com/en-us/library/…跨度>
  • 谢谢。但我不明白为什么建议的代码会解决问题。是不是因为你没有打电话给Dispose()
  • @Lijo 因为您没有可重现的示例,所以不可能多谈“解决问题”。我的建议很简单:您可以很容易地引入细微的错误 - 这是有风险的、不必要的,还有更多工作永远不会编写的不必要的代码没有任何错误。
  • 我喜欢这一点 - code that never gets written doesn't have any bugs in it :-)
  • @nWorx 为了让其他阅读本文的人清楚, using(var tran = connection.BeginTransaction()) 内部未处理的异常将导致 tran 在结束时被回滚using 块(请注意,根据MSDN 文档,此行为特定于 DbTransaction.Dispose 实现)。异常本身不会导致 tran 回滚。
【解决方案3】:

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

那么下一个错误This SqlTransaction has completed 将出现在transaction.RollBack(); 上,并且它的调用堆栈也包含ZombieCheck()

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

所以我猜这个错误的原因之一可能是连接中的错误,然后导致 transaction 错误也发生。

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

            }
        }
    }
}

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

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

或者如果在提交之前关闭连接也会调用这个错误。

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

更新:

奇怪的是我又新建了一张表,往里面插入了50万条数据,

然后用select * from newtable sql使用100000个任务,同时运行5个程序,这次出现超时错误,但是transaction.Rollback()时没有调用SQLTransaction has completed error

但是如果发生超时错误,则跳转到catch块,在catch块中再次执行transaction.Commit()SQLTransaction has completed error就会发生。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-15
        • 2014-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-21
        相关资源
        最近更新 更多