【问题标题】:Why is System.Transactions TransactionScope default Isolationlevel Serializable为什么 System.Transactions TransactionScope 默认 Isolationlevel Serializable
【发布时间】:2012-07-02 11:29:11
【问题描述】:

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

有什么想法吗?

【问题讨论】:

  • 将样板代码移动到辅助方法中,这个问题将永远不会再困扰您。

标签: c# transactionscope isolation-level


【解决方案1】:

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

DTC 使用原生 ISOLATIONLEVEL 枚举:

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

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

现在,下一个问题是:为什么 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>设置。

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

【讨论】:

    【解决方案2】:

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

    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
    }
    

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

    【讨论】:

    • 这实际上与我所做的相同,因为我有一个中心位置可以为我的用例获取“默认”事务范围
    【解决方案3】:

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

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

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

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

    【讨论】:

    • “你可以将一个完美运行的应用程序渲染成一个损坏的应用程序”+1
    • 请注意,即使是可序列化的隔离级别也不能保证不会出现货币问题。
    • @Christian.K 感谢您的回答。你是对的——只有设计师知道。也许我只是对可序列化有问题,因为当我听到隔离级别时,我倾向于想到数据库。可序列化可能是其他事务提供程序的一个很好的默认值。
    猜你喜欢
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    相关资源
    最近更新 更多