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

Ber*_*her 67 c# transactionscope isolation-level

我只是想知道使用Serializable作为默认Isolationlevel的一个很好的理由可能是在创建System.Transactions TransactionScope时,因为我想不出任何(并且似乎你不能改变默认值,web/app.config所以你总是要设置它你的代码)

using(var transaction = TransactionScope()) 
{
    ... //creates a Transaction with Serializable Level
}
Run Code Online (Sandbox Code Playgroud)

相反,我总是要写这样的样板代码:

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

using(var transaction = new TransactionScope(TransactionScopeOption.Required, txOptions)) 
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Sim*_*ier 82

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

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>.明确设置 .

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


Alm*_*ond 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);
    } 
}
Run Code Online (Sandbox Code Playgroud)

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

using (var scope = TransactionScopeBuilder.CreateReadCommitted())
{
    //do work here
}
Run Code Online (Sandbox Code Playgroud)

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


Chr*_*n.K 27

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

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

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

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

  • "你可以为一个破碎的人提供一个完美的应用程序"+1 (3认同)
  • 请注意,即使是可序列化的隔离级别仍然无法保证不会发生货币问题. (2认同)