14

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

此 SQLTransaction 已完成;它不再可用

堆栈跟踪附在下面——它说关于Zombie CheckRollback

代码中的错误是什么?

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

更新

来自MSDN - SqlTransaction.Rollback 方法

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

僵尸检查交易 - 错误

我在各种应用程序中看到此错误的最常见原因之一是在我们的应用程序中共享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. 什么是僵尸交易?
  2. 僵尸检查交易 - 错误
  3. SqlTransaction 已完成
  4. http://forums.asp.net/t/1579684.aspx/1
  5. “此 SqlTransaction 已完成;它不再可用。”... 配置错误?
  6. dotnet.sys-con.com - SqlClient 连接池暴露
  7. 线程中止留下僵尸事务和损坏的 SqlConnection

4

5 回答 5

8

您应该将一些工作留给编译器,以便为您将其包装在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 文档页面中完全复制的 Rollback method 。

我看到你担心你有一个僵尸交易。如果你粘贴了,听起来你没有问题。你的交易已经完成,你不应该再与它有任何关系。如果您持有它们,请删除对它的引用,然后忘记它。


来自MSDN - SqlTransaction.Rollback 方法

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

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

于 2013-03-08T12:18:02.873 回答
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;
         }
    }
}

出错的代码要少得多。

于 2013-03-08T12:12:57.053 回答
2

我使用下面的代码可以重现这个错误,我使用 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);

            }
        }
    }
}

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

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

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

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

更新:

我发现我创建另一个新表并向其中插入 50 万条数据很奇怪,

然后用select * from newtablesql 使用 100000 个任务,同时运行 5 个程序,这次出现 Timeout Error,但是当transaction.Rollback()它没有调用SQLTransaction has completed error.

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

于 2017-06-07T09:15:33.710 回答
1
于 2016-05-30T15:05:27.427 回答
0

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

于 2015-11-10T10:53:33.847 回答