4

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

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

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

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

如果方法A()想要一个快照级别并调用想要读取已提交级别的方法 B()。方法A()在我开发的 LibraryA 中,方法B()在由一家虚构公司开发的 LibraryB 中。A()如何在不获取ArgumentException的情况下调用B()

4

3 回答 3

3

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

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

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

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

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

不管怎样,数据库服务器无法判断实际需求是否兼容,所以它完全放弃了这个问题。

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

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

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

祝你好运!

于 2010-08-24T14:39:29.053 回答
0

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

看看这个stackpost

阅读隔离备注

于 2015-10-12T01:53:11.823 回答
0

是的。您可以嵌套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
    }

}
于 2022-02-01T18:48:41.383 回答