为什么System.Transactions TransactionScope默认为Isolationlevel可序列化


75

我只是想知道在创建System.Transactions TransactionScope使用Serializable作为默认Isolationlevel的一个很好的理由是什么,因为我想不到任何原因(而且似乎无法更改默认值,因此您总是必须在其中设置它您的代码) web/app.config

using(var transaction = TransactionScope()) 
{
    ... //creates a Transaction with Serializable Level
}

相反,我总是不得不像这样编写样板代码:

var txOptions = new System.Transactions.TransactionOptions();
txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;

using(var transaction = new TransactionScope(TransactionScopeOption.Required, txOptions)) 
{
    ...
}

有任何想法吗?


1
将样板代码移动到辅助方法中,此问题将再也不会困扰您。
usr

Answers:


91

事实Serializable是默认值来自于甚至没有从DTC(分布式事务处理协调器)编程发布.NET的时期(在1999年之前)。

DTC使用本机ISOLATIONLEVEL枚举:

ISOLATIONLEVEL_SERIALIZABLE 当前事务读取之前,当前事务读取的数据不能被另一个事务更改。不能插入任何会影响当前交易的新数据。这是最安全的隔离级别,并且是默认设置,但是允许最低的并发级别。

.NETTransactionScope建立在这些技术之上。

现在,下一个问题是:为什么DTC定义ISOLATIONLEVEL_SERIALIZABLE为默认交易级别?我想这是因为DTC是在1995年左右(肯定是在1999年之前)设计的。当时,SQL标准是SQL-92(或SQL2)。

这是SQL-92关于事务级别的内容:

SQL事务的隔离级别为READ UNCOMMITTED,READ COMMITTED,REPEATABLE READ或SERIALIZABLE。SQL事务的隔离级别定义了SQL事务中的SQL数据或架构上的操作受并发SQL事务中的影响影响的程度,并可能影响SQL数据或架构上的操作。默认情况下,SQL事务的隔离级别为SERIALIZABLE。级别可以由明确设置<set transaction statement>

保证在隔离级别SERIALIZABLE上执行并发SQL事务是可序列化的。可序列化的执行被定义为同时执行SQL事务的操作的执行,该操作产生与那些相同的SQL事务的某些串行执行相同的效果。串行执行是指每个SQL事务在下一个SQL事务开始之前执行完成的过程。


51

减少编写样板代码的有用方法是将其包装在如下的builder类中:

public static class TransactionScopeBuilder
{
    /// <summary>
    /// Creates a transactionscope with ReadCommitted Isolation, the same level as sql server
    /// </summary>
    /// <returns>A transaction scope</returns>
    public static TransactionScope CreateReadCommitted()
    {
        var options = new TransactionOptions
        {
            IsolationLevel = IsolationLevel.ReadCommitted,
            Timeout = TransactionManager.DefaultTimeout
        };

        return new TransactionScope(TransactionScopeOption.Required, options);
    } 
}

然后,您可以在创建事务范围时像这样使用它:

using (var scope = TransactionScopeBuilder.CreateReadCommitted())
{
    //do work here
}

您可以根据需要将其他常见事务范围缺省值添加到构建器类。


1
这实际上是我做的一样的事情,我有一个中心位置来获取我的用例的“默认” Transactionscope
Bernhard Kircher

29

好吧,我想这是“只有设计师一定会知道”这类问题之一。但是无论如何,这是我的两分钱:

虽然“可序列化”是最“限制”的隔离级别(关于锁定,基于锁的RDBMS中,因此并发访问,死锁等),但它也是最“安全”的隔离级别(关于数据的一致性)。

因此,尽管在像您这样的场景中需要额外的工作(在那之前已经完成了;-),但默认情况下选择最安全的变体还是有意义的。SQL Server(T / SQL)选择使用READ COMMITTED,显然是出于其他原因:-)

然后通过配置使其可更改将不是一个好主意,因为通过摆弄配置,您可以将完美运行的应用程序呈现给损坏的应用程序(因为它可能根本无法与其他任何应用程序一起使用)。或者通过“硬编码”隔离级别来扭转论点,您可以确保您的应用程序按预期运行。可以说,隔离级别不适用于配置选项(而事务超时的确是)。


3
“您可以为出现故障的应用程序提供完美的应用程序” +1
史蒂文·

2
请注意,即使是隔离级别的可序列化,仍然不能保证不会发生任何货币问题。
2012年

@ Christian.K感谢您的回答。您是对的-只有设计师知道。也许我只是对可序列化有问题,因为当我听到隔离级别时,我倾向于想到一个数据库。对于其他事务提供程序,可序列化可能是一个很好的默认设置。
Bernhard Kircher
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.