ADO.NET僵尸交易bug?如何确保命令不会在隐式事务上执行?

时间:2010-06-07 14:33:05

标签: sql-server ado.net transactions implicit zombie-process

e.g。发生死锁时,即使SQL命令已经分配了回滚后的SQL事务,也会成功执行以下SQL命令。看起来,它是由在SQL Server上创建的新隐式事务引起的。

有人可能会认为ADO.NET会抛出一个异常,即在僵尸事务上执行命令。但是,不会抛出这种异常。 (我认为这是ASP.NET中的一个错误。)此外,由于僵尸事务,最终Dispose()默默地忽略了回滚。

任何想法,我如何确保没有人可以在隐式事务上执行命令? 或者,如何检查该交易是僵尸?我发现Commit()Rollback()会检查zombie事务,但是我可以将它们称为测试:)

我还发现读取IsolationLevel也会进行检查,但我不确定未来的优化器是否会删除简单的调用transaction.IsolationLevel.ToString();。或者您是否知道任何其他安全方式调用getter(不使用反射或IL发射)?

  编辑:Remus Rusanu指出这种情况通常不会发生。是的,这是真的。通常在代码中存在错误时发生。在我们的例子中,finally语句中有一些日志记录例程试图将故障存储到数据库中。现在,我正在尝试找到一种解决方案,以便在将来检测此类错误。由于这些错误很难测试。如果ADO.NET会检查提供的事务是否为僵尸,则可以更容易地找到此错误。我发现了两种可能性:

  1. 关闭隐式交易的创建 - 我不确定这是否可行。
  2. 确保在执行任何命令之前,检查zombie事务是否会运行。

3 个答案:

答案 0 :(得分:2)

您描述的内容不存在。事务回滚将在您的应用程序中引发一个非常明显的异常。出于某种原因,我更宁愿相信你的代码捕获异常并默默地忽略它,在事务回滚后继续执行语句。

答案 1 :(得分:0)

可能与您的问题没有直接关系,因为它是由错误引起的,但仍然可能有意义。并非所有错误都会导致事务回滚,因此有时某个事务可能“部分成功” - 某些语句错误而其他语句完全正常。
有一个选项SET XACT_ABORT ON使服务器在任何错误上中止事务。

考虑到您的问题,您无法关闭隐式事务(如果执行SQL语句,将创建隐式事务,除非另一个事务已处于活动状态)。因此,您必须正确处理错误,以确保在您需要时可以进行交易 查看TransactionScope类,您可以使用它来避免在代码中管理这些事务。

答案 2 :(得分:0)

//根据您的描述,我猜测您的代码有效地执行了此操作

        SqlConnection conn = new SqlConnection("ConnectionString");
        SqlCommand cmd = new SqlCommand("insert into ....");

        cmd.Connection = conn;

        conn.Open();

        SqlTransaction tran = conn.BeginTransaction();


        cmd.Transaction = tran;

        tran.Rollback(); //or tran.Dispose();

        cmd.ExecuteNonQuery();

这会导致cmd在事务范围之外执行。

删除行cmd.Connection = conn;将实现我认为您正在寻找的行为(例如,该命令将失败,因为该事务不再有效。)

SqlConnection conn = new SqlConnection("ConnectionString");
    SqlCommand cmd = new SqlCommand("insert into ....");

    //cmd.Connection = conn;

    conn.Open();

    SqlTransaction tran = conn.BeginTransaction();
    cmd.Connection = tran.Connection;

    cmd.Transaction = tran;

    tran.Rollback(); //or tran.Dispose();

    cmd.ExecuteNonQuery();