嵌套/子TransactionScope回滚

Rob*_*ner 27 .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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我不能使用Suppress或RequiresNew选项,因为Trn B依赖于Trn A插入的数据.如果我确实使用这些选项,Trn B被Trn A阻止.

任何想法如何让它工作,或甚至可能使用System.Transactions命名空间?

谢谢

Aar*_*ght 48

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

在嵌套范围内投票

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

(来自使用事务范围实现隐式事务)

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

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

事实上,SQL Server不都支持真正的嵌套事务,虽然它可能的(虽然有点不直观),以实现与适当使用相同的最终结果SAVE TRAN声明.如果您需要此特定行为,则将此逻辑重新实现为存储过程(或其中几个)可能是您的最佳选择.

  • @Alireza:OP希望有选择地提交某些内部事务,同时回滚未明确提交的所有*else*.你的"简单解决方案"正是`TransactionScope`的工作方式,并且记录在案,并且通过这个答案清楚地解释了,但如果外部范围没有完成,它实际上不会提交任何内部范围的更改.使用`System.Transactions`根本不可能. (3认同)
  • 谢谢,这就解释了。老实说,我仍然从罗伯特的问题中得到错误的含义!! (2认同)