我正在尝试嵌套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命名空间?
由于
答案 0 :(得分:47)
你可能不会喜欢这个答案,但是......
在嵌套范围内投票
虽然嵌套作用域可以加入根作用域的环境事务,但在嵌套作用域中调用完整不会影响根作用域。只有当从根范围到最后一个嵌套范围的所有范围都投票提交事务时,才会提交事务。
(来自Implementing an Implicit Transaction using Transaction Scope)
遗憾的是,TransactionScope
类没有提供任何机制(我知道)用于隔离工作单元。这是全有或全无。您可以使用TransactionScopeOption.Suppress
阻止任何事务在特定工作单元上发生,但这可能不是您想要的,因为您将失去该范围内的任何内容的原子性。
使用TransactionScope
时,只有一个“环境”事务。一旦TransactionScope
被处置或收集而没有Complete
被执行,整个环境事务就会被回滚;就是这样,游戏结束。
实际上,SQL Server根本不支持真正的嵌套事务,尽管 可能(虽然有点不直观)通过适当使用SAVE TRAN
语句来实现相同的最终结果。如果您需要此特定行为,则将此逻辑重新实现为存储过程(或其中几个)可能是您的最佳选择。