it-roy-ru.com

Почему System.Transactions TransactionScope по умолчанию Isolationlevel Serializable

Мне просто интересно, какая веская причина использовать Serializable в качестве уровня изоляции по умолчанию может быть при создании System.Transactions TransactionScope , потому что я не могу думать ни о чем (и кажется, что вы не можете изменить значение по умолчанию с помощью 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)) 
{
    ...
}

Есть идеи?

66
Bernhard Kircher

Тот факт, что Serializable используется по умолчанию, происходит из-за того, что .NET даже не был выпущен (до 1999 года), из-за программирования DTC ( Координатор распределенных транзакций ).

DTC использует собственное перечисление ИЗОЛЯЦИОННЫЙ УРОВЕНЬ :

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-транзакции.

82
Simon Mourier

Полезный способ сократить написание шаблонного кода - это обернуть его в класс построителя следующим образом:

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
}

Вы можете добавить другие общие значения по умолчанию для области транзакции в класс построителя по мере необходимости.

46
Almond

Ну, я думаю, это один из тех вопросов, которые "только дизайнер определенно знает". Но вот мои два цента в любом случае:

Хотя Serializable является наиболее "ограничивающим" уровнем изоляции (относительно блокировки, в СУБД на основе блокировок и, следовательно, одновременного доступа, взаимоблокировок и т.д.), Он также является наиболее "безопасным" уровнем изоляции (относительно согласованности данных).

Поэтому, требуя дополнительной работы в таких сценариях, как ваш (там уже было сделано ;-), имеет смысл выбрать самый безопасный вариант по умолчанию. SQL Server (T/SQL) выбирает использовать READ COMMITTED , очевидно, по другим причинам :-)

Делать его изменяемым по конфигурации, тогда было бы плохой идеей, потому что, манипулируя конфигурацией, вы могли бы преобразовать идеально работающее приложение в сломанное (потому что оно могло бы просто не быть предназначено для работы с чем-либо еще). Или, чтобы изменить аргумент, "жестко закодировав" уровень изоляции, вы можете убедиться, что ваше приложение работает так, как ожидалось. Возможно, уровень изоляции не подходит для параметра конфигурации (хотя время ожидания транзакции действительно есть).

27
Christian.K