使用对象初始化构造的嵌套事务范围会导致错误。

5
在我的C#代码中,我正在使用嵌套事务范围。我有一个实用类,可以完全相同地创建TransactionScope对象。外部范围和内部范围都是以完全相同的方式构建的。
如果我像下面的第一个示例那样构造TransactionScope对象,嵌套的事务范围将很好地协同工作:
public static TransactionScope CreateTransactionScope()
{
   var transactionOptions = new TransactionOptions();
   transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
   transactionOptions.Timeout = TransactionManager.MaximumTimeout;
   return new TransactionScope(TransactionScopeOption.Required, transactionOptions);
}

然而,如果我像这样构造TransactionScope对象,就会出现异常:
public static TransactionScope CreateTransactionScope()
{
   var transactionOptions = new TransactionOptions
   {
      IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted,
      Timeout = TransactionManager.MaximumTimeout
   };
   return new TransactionScope(TransactionScopeOption.Required, transactionOptions);
}

错误信息为:“为TransactionScope指定的事务具有与作用域请求的值不同的隔离级别。参数名:transactionOptions.IsolationLevel”。
有人能否解释一下为什么使用对象初始化会导致这种情况发生?

你找到问题了吗? - Saeed Neamati
2个回答

3

当外部事务隔离级别与您要分配给事务范围的隔离级别不同时,会出现此错误。

这意味着,在调用您的方法并尝试分配所需的隔离级别时,事务管理器检测到存在具有不同隔离级别的现有事务,并引发异常。

var transactionOptions = new TransactionOptions
{
   IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted,
   Timeout = TransactionManager.MaximumTimeout
};

return new TransactionScope(TransactionScopeOption.RequiredNew,TransactionOptions);

RequireNew强制创建一个新的内部事务。我建议进行动态检查,以确定当前的隔离级别是否与以下内容类似:

if (Transaction.Current != null && Transaction.Current.IsolationLevel != myIsolationLevel)
{
   scopeOption = TransactionScopeOption.RequiresNew;
}

编辑:如评论中建议的那样,值得一提的是,RequiresNew确实会创建一个新事务,并且由于其本质上与外部事务隔离,因此是独立的。我找到了一篇非常好的文章,非常清楚地解释了事务在这里是如何工作的:https://www.codeproject.com/articles/690136/all-about-transactionscope


使用 TransactionScopeOption.RequiresNew 会导致嵌套事务之间相互独立。例如,如果内部事务被回滚,则外部事务的更改不会被回滚。通常情况下,您不希望出现这种情况,因此我认为在答案中提到这一点非常重要。 - ajbeaven

1

你确定只是替换上述方法就会导致异常吗?它们在功能上应该是完全等效的。

只是运行这两个变体是可以的:

using (var aa1 = CreateTransactionScopeGood())
    using (var aa2 = CreateTransactionScopeGood())
        Console.WriteLine("this will be printed");

using (var aa1 = CreateTransactionScopeBad())
    using (var aa2 = CreateTransactionScopeBad())
        Console.WriteLine("this will be printed");

您能提供一种重现它的方法吗?

然而,我只能在同一事务中混合不同的IsolationScope时重现您的异常,这确实会导致异常:

using (new TransactionScope(TransactionScopeOption.Required, new
        TransactionOptions { IsolationLevel = IsolationLevel.Chaos }))
    using (new TransactionScope(TransactionScopeOption.Required, new
            TransactionOptions { IsolationLevel = IsolationLevel.Serializable }))
        Console.WriteLine("this will not be printed");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接