【问题标题】:Inner TransactionScope with different IsolationLevel, how can it be achieved?不同IsolationLevel的Inner TransactionScope,如何实现?
【发布时间】:2010-08-24 14:21:37
【问题描述】:

TransactionScope 的当前实现缺乏在嵌套范围内更改 IsolationLevels 的能力。

MSDN 声明:当使用嵌套的 TransactionScope 对象时,所有嵌套的范围必须配置为使用完全相同的隔离级别才能加入环境事务。如果嵌套的 TransactionScope 对象尝试加入环境事务但它指定了不同的隔离级别,则会抛出 ArgumentException

但是 SQL Server 允许我们随时更改隔离级别,为什么 TransactionScope 不允许?没看懂。

BCL 中是否有任何关于嵌套 SQL 事务及其隔离级别的标准来禁止这种行为。我有哪些选择?我当然不能仅仅为了它们可以使用而设计类库并与它们一起提升隔离级别。

如果方法 A() 想要一个 Snapshot 级别并调用想要 Read Committed 级别的方法 B()。 A() 方法在我开发的 LibraryA 中,B() 方法在由一家虚构公司开发的 LibraryB 中。 A() 如何调用 B() 而不会得到 ArgumentException

【问题讨论】:

    标签: .net ado.net transactionscope system.transactions


    【解决方案1】:

    这是一个理论问题,而不是任何特定产品。基本上,事务的原始概念是具有所有 ACID 属性的东西:原子、一致、隔离和持久。

    http://databases.about.com/od/specificproducts/a/acid.htm

    现在,考虑一下“隔离级别”的含义:本质上,出于性能或其他原因,我们可能会选择放弃数据库对 ACIDity 所做的部分或全部保证。隔离和原子性密切相关,就像彼此的对偶一样。打破一个,另一个受苦。

    通常将事务分解为在特定 SQL 语句中可单独表达的部分,但为了保证完全有帮助,您需要将它们包装在一个至少具有足够隔离性的事务中,以使整个 shmear 正常工作正确。

    现在,如果您的部分事务需要更高程度的隔离,那么整个事务也需要,否则它可能会在敏感部分中断。相反,如果某个部分的隔离级别较低,那么很可能该部分的正确功能需要较少的隔离。 (不要让我想出一个很好的例子来说明什么时候是真的。)

    反正数据库服务器无法判断实际需求是否兼容,所以干脆放弃这个问题。

    真正应该发生的是人们开发他们需要的交易。我意识到这并不总是那么容易,但鉴于您的业务数据架构是您自己的,因此将随机 SQL 组件插入在一起并不容易。

    在处理集中式数据库(如 SQL Server)的情况下,最佳做法是设计整个事务,然后当您注意到设计之间的共性时,您可以在编写繁琐的代码之前将其分解。

    如果您确实需要在不同的数据存储库(或类似存储库)之间进行协调,则需要使用分布式事务管理器。它是一个单独的产品,甚至比数据库服务器更难做好。但这对于像 ATM 这样的东西来说是必要的,它要么给你钱,要么不给你钱,要么打你的银行账户,要么不打你的银行账户,这两者必须匹配。

    祝你好运!

    【讨论】:

    • 感谢您的回复。但是我缺少的是为什么如果 SQL Server 允许更改事务的隔离级别,那么框架会禁止它?有时你可能真的需要这个用于一些优化目的的子语句,我真的不想自己改变 SQL 语句的级别。
    • @IvanZlatanov TransactionScope 不限于与 SQL Server 一起使用,它可以允许跨进程/系统的分布式事务。所以它比 SQL Server 允许的更严格,可能会简化确保跨系统一致性的复杂性,而不是支持分布式事务。
    • @AaronLS 从来没有这样想过。很有道理。
    【解决方案2】:

    我发现自己遇到了麻烦,一旦我猜到异常选项澄清了所有问题,而您无法实现类似的事情可以做。事实是,如果您切换隔离级别,则每个连接只允许一个隔离级别,然后整个隔离级别都会更改,直到嵌套完成。

    查看thisstackpost

    阅读isolation remarks

    【讨论】:

      【解决方案3】:

      是的。您可以嵌套具有不同隔离级别的TransactionScopes

      正如你的报价所说

      如果要加入环境事务,所有嵌套范围必须配置为使用完全相同的隔离级别

      因此,如果B 可能需要与环境事务不同的隔离级别,只需确保它不会与TransactionScopeOption.RequiresNew 一起加入环境事务

      void A()
      {
          var options = new TransactionOptions() 
          {
              IsolationLevel = IsolationLevel.Snapshot 
          }
          using (var transaction = new TransactionScope(TransactionScopeOption.Required, options))
          {
              B();
          }
      
      }
      
      void B()
      {
          var options = new TransactionOptions()
          {
              IsolationLevel = IsolationLevel.ReadCommitted,
          };
          // RequiresNew is the important bit
          using (var transaction = new TransactionScope(TransactionScopeOptions.RequiresNew, options))
          {
              // Do stuff
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-07
        • 1970-01-01
        相关资源
        最近更新 更多