79

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

有任何想法吗?

4

3 回答 3

95

事实上Serializable,默认值来自于 .NET 甚至还没有发布的时候(1999 年之前),来自 DTC(分布式事务协调器)编程。

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 数据或模式的操作。SQL 事务的隔离级别默认为 SERIALIZABLE。级别可以由<set transaction statement>.

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

于 2014-04-28T14:14:31.013 回答
52

减少编写样板代码的一种有用方法是将其包装在构建器类中,如下所示:

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
}

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

于 2013-03-07T01:45:02.167 回答
29

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

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

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

让它可以通过配置改变,这将是一个坏主意,因为通过摆弄配置,您可以将一个完美运行的应用程序渲染为一个损坏的应用程序(因为它可能根本无法与其他任何东西一起使用)。或者为了扭转争论,通过“硬编码”隔离级别,您可以确保您的应用程序按预期工作。可以说,隔离级别不适合配置选项(而事务超时确实如此)。

于 2012-07-02T11:48:46.350 回答