sql server 2008-为什么即使从未调用TransactionScope.Complete()也要提交嵌套事务



我正在测试嵌套事务是如何工作的,并发现了这种令人不安和意外的行为。

using(TransactionScope otx = new TransactionScope())
using(SqlConnection conn1 = new SqlConnection("Server=S;Database=DB;Trusted_Connection=yes"))
using(SqlCommand cmd1 = conn1.CreateCommand())
{
    conn1.Open();
    cmd1.CommandType = CommandType.Text;
    cmd1.CommandText = "INSERT INTO FP.ACLs (ChangeToken,ACL) VALUES (1,0x)";
    cmd1.ExecuteNonQuery();
    using(TransactionScope itx = new TransactionScope(TransactionScopeOption.RequiresNew))
    using(SqlConnection conn2 = new SqlConnection("Server=S;Database=DB;Trusted_Connection=yes"))
    using(SqlCommand cmd2 = conn1.CreateCommand())
    {
        conn2.Open();
        cmd2.CommandType = CommandType.Text;
        cmd2.CommandText = "INSERT INTO FP.ACLs (ChangeToken,ACL) VALUES (2,0x)";
        cmd2.ExecuteNonQuery();
        // we don't commit the inner transaction
    }
    otx.Complete(); // nonetheless, the inner transaction gets committed here and two rows appear in the database!
}

我看到了另一个问题,但解决方案并不适用。

如果我没有指定TransactionScopeOption.RequiresNew(即,我不使用嵌套事务,只使用嵌套作用域),那么当内部作用域未完成时,整个事务将回滚,并且在调用otx时出错。完成()。这很好。

但是,当嵌套事务没有成功完成时,我当然不希望它被提交!有人知道这里发生了什么吗?我如何才能得到预期的行为?

数据库为SQL Server 2008 R2。

首先,SQL Server中没有嵌套事务。这很重要。

其次,两个TransactionScope都使用conn1,因此(在SQL Server级别)为每个BEGIN TRANSACTION 递增@@TRANCOUNT

简单解释:内部事务在外部事务提交时提交,因为回滚内部事务会回滚两个事务

也就是说,COMMIT TRANSACTION(由.Complete.Dispose暗示)使@@TRANCOUNT递减,而ROLLBACK TRANSACTION(仅由.Dispose暗示)将其带回零。因此内部回滚被抑制,因为"没有嵌套事务"

如果您在内部作用域中正确使用了conn2,它将按预期工作,因为这两个事务在数据库服务器级别是不相关的。这才是最重要的。。。

您的第二个Command对象是在conn1上创建的,而不是在conn2上,所以这与另一个问题非常相似——您运行命令的连接是在第二个事务作用域打开之前打开的。

相关内容

  • 没有找到相关文章

最新更新