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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11292763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 17:16:16  来源:igfitidea点击:

Why is System.Transactions TransactionScope default Isolationlevel Serializable

c#transactionscopeisolation-level

提问by Bernhard Kircher

I am just wondering what a good reason to use Serializableas the default Isolationlevel may be when creating a System.TransactionsTransactionScope, because I cannot think of any (and it seems that you cannot change the default via web/app.configso you always have to set it in your code)

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

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

Instead I always have to write boilerplate code like this:

相反,我总是必须像这样编写样板代码:

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

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

Any ideas?

有任何想法吗?

采纳答案by Simon Mourier

The fact Serializableis the default comes from times when .NET wasn't even released (before year 1999), from DTC (Distributed Transaction Coordinator) programming.

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

DTC uses a native ISOLATIONLEVELenumeration:

DTC 使用本地ISOLATIONLEVEL枚举:

ISOLATIONLEVEL_SERIALIZABLEData read by a current transaction cannot be changed by another transaction until the current transaction finishes. No new data can be inserted that would affect the current transaction. This is the safest isolation level and is the default, but allows the lowest level of concurrency.

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

.NET TransactionScopeis built on top of these technologies.

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

Now, the next question is: why DTC defines ISOLATIONLEVEL_SERIALIZABLEas the default transaction level? I suppose it's because DTC was designed around year 1995 (before 1999 for sure). At that time, the SQL Standard was SQL-92 (or SQL2).

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

And here is what SQL-92says about transaction levels:

以下是SQL-92关于事务级别的说明:

An SQL-transaction has an isolation level that is READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, or SERIALIZABLE. The isolation level of an SQL-transaction defines the degree to which the operations on SQL-data or schemas in that SQL-transaction are affected by the effects of and can affect operations on SQL-data or schemas in concurrent SQL-transactions. The isolation level of a SQL- transaction is SERIALIZABLE by default. The level can be explicitly set by the <set transaction statement>.

The execution of concurrent SQL-transactions at isolation level SERIALIZABLE is guaranteed to be serializable. A serializable execution is defined to be an execution of the operations of concurrently executing SQL-transactions that produces the same effect as some serial execution of those same SQL-transactions. A serial execution is one in which each SQL-transaction executes to completion before the next SQL-transaction begins.

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

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

回答by Christian.K

Well, I guess this is one of those "only the designer would definitely know" type of questions. But here are my two cents anyhow:

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

While Serializable is the most "limiting" isolation level (concerning locking, in a lock-based RDBMS, and thus concurrent access, deadlocks, etc.) it is also the most "safe" isolation level (concerning consistency of data).

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

So while requiring extra work in scenarios like yours (been there done that ;-), it make sense to opt for the safest variant by default. SQL Server (T/SQL) chooses to use READ COMMITTED, obviously applying other reasons :-)

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

Making it changeable by configuration, would then be a bad idea, because by fiddling with configuration you could render a perfectly working application to a broken one (because it might simply not be designed to work with anything else). Or to turn the argument around, by "hardcoding" the isolation level, you can make sure that your application works as expected. Arguably, the isolation level is not a good fit for a configuration option (while the transaction timeoutindeed is).

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

回答by Almond

A useful way to cut down writing boilerplate code is to wrap it in a builder class like so:

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

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);
    } 
}

Then you can use it like this when creating a transaction scope:

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

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

You can add other common transaction scope defaults to the builder class as you need them.

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