即使从未调用TransactionScope.Complete(),为什么提交嵌套事务?

1 transactions transactionscope system.transactions sql-server-2008

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

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!
}
Run Code Online (Sandbox Code Playgroud)

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

如果我没有指定TransactionScopeOption.RequiresNew(即我不使用嵌套事务,只是嵌套作用域),则在内部作用域未完成时回滚整个事务,并在调用otx.Complete时发生错误().这可以.

但我当然不希望嵌套事务在未成功完成时提交!有谁知道这里发生了什么以及我如何能够获得预期的行为?

该数据库是SQL Server 2008 R2.

gbn*_*gbn 6

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

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

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

也就是说,COMMIT TRANSACTION(隐含的.Complete.Dispose)减少@@TRANCOUNTROLLBACK TRANSACTION(.Dispose仅暗示)将其恢复为零.所以内部回滚被抑制,因为"没有嵌套事务这样的东西"

如果你在内部'范围内正确使用了conn2,那么它将按预期工作,因为在数据库服务器级别上2个事务是不相关的.哪个是重要的......