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会检查提供的事务是否为僵尸,则可以更容易地找到此错误。我发现了两种可能性:
答案 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();