嵌套/子TransactionScope回滚

时间:2010-04-30 02:36:06

标签: .net transactions transactionscope

我正在尝试嵌套TransactionScopes(.net 4.0),就像在SQL Server中嵌套事务一样,但看起来它们的运行方式不同。我希望我的子事务能够在它们失败时回滚,但允许父事务决定是否提交/回滚整个操作。问题是当第一次完成时,事务被回滚。我意识到完全不同于提交。

我正在尝试做的一个非常简化的例子:

static void Main(string[] args)
{
    using(var scope = new TransactionScope()) // Trn A
    {
        // Insert Data A

        DoWork(true);
        DoWork(false);

        // Rollback or Commit
    }
}

// This class is a few layers down
static void DoWork(bool fail)
{
    using(var scope = new TransactionScope()) // Trn B
    {
        // Update Data A

        if(!fail)
        {
            scope.Complete();
        }
    }
}

我无法使用Suppress或RequiresNew选项,因为Trn B依赖于Trn A插入的数据。如果我使用这些选项,则Trn B被Trn A阻止。

我是如何让它工作的,或者是否甚至可以使用System.Transactions命名空间?

由于

1 个答案:

答案 0 :(得分:47)

你可能不会喜欢这个答案,但是......

  

在嵌套范围内投票

     

虽然嵌套作用域可以加入根作用域的环境事务,但在嵌套作用域中调用完整不会影响根作用域。只有当从根范围到最后一个嵌套范围的所有范围都投票提交事务时,才会提交事务。

(来自Implementing an Implicit Transaction using Transaction Scope

遗憾的是,TransactionScope类没有提供任何机制(我知道)用于隔离工作单元。这是全有或全无。您可以使用TransactionScopeOption.Suppress阻止任何事务在特定工作单元上发生,但这可能不是您想要的,因为您将失去该范围内的任何内容的原子性。

使用TransactionScope时,只有一个“环境”事务。一旦TransactionScope被处置或收集而没有Complete被执行,整个环境事务就会被回滚;就是这样,游戏结束。

实际上,SQL Server根本不支持真正的嵌套事务,尽管 可能(虽然有点不直观)通过适当使用SAVE TRAN语句来实现相同的最终结果。如果您需要此特定行为,则将此逻辑重新实现为存储过程(或其中几个)可能是您的最佳选择。