为什么System.Transactions TransactionScope默认为Isolationlevel Serializable

时间:2012-07-02 11:29:11

标签: c# transactionscope isolation-level

我只是想知道在创建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)) 
{
    ...
}

有什么想法吗?

3 个答案:

答案 0 :(得分:81)

事实Serializable是默认来自.NET甚至没有发布(1999年之前),来自DTC(Distributed Transaction Coordinator)编程。

DTC使用原生ISOLATIONLEVEL枚举:

  

<强> ISOLATIONLEVEL_SERIALIZABLE   当前事务读取的数据不能   在当前交易之前被另一笔交易更改   饰面。不能插入会影响当前的新数据   交易。 这是最安全的隔离级别,是默认值,   但允许最低级别的并发。

.NET TransactionScope建立在这些技术之上。

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

以下是SQL-92关于交易级别的说法:

  

SQL事务的隔离级别为READ UNCOMMITTED,   READ COMMITTED,REPEATABLE READ或SERIALIZABLE。隔离级别   SQL事务的定义了操作的程度   SQL事务中的SQL数据或模式受到   影响和影响对SQL数据或模式的操作   并发SQL事务。 SQL事务的隔离级别   默认为SERIALIZABLE 。级别可以由。明确设置   <set transaction statement>

     

在隔离级别执行并发SQL事务   SERIALIZABLE保证可序列化。可序列化的exe-   cution被定义为执行同意的操作   正在执行产生与之相同效果的SQL事务   一些串行执行那些相同的SQL事务。连续执行   cution是每个SQL事务执行完成的一个   在下一个SQL事务开始之前。

答案 1 :(得分:46)

减少编写样板代码的一种有用方法是将它包装在类似的构建器类中:

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
}

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

答案 2 :(得分:27)

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

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

因此,虽然在像你这样的场景中需要额外的工作(在那里做了;-),默认情况下选择最安全的变体是有意义的。 SQL Server(T / SQL)选择使用READ COMMITTED,显然应用其他原因: - )

通过配置使其可更改将是一个坏主意,因为通过摆弄配置,您可以将完美的应用程序呈现给损坏的应用程序(因为它可能根本不适用于其他任何东西)。或者通过“硬编码”隔离级别来改变参数,可以确保应用程序按预期工作。可以说,隔离级别不适合配置选项(而transaction timeout确实是这样)。