Чому System.Transaction TransactionScope за замовчуванням Isolationlevel level Serializable


75

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

Будь-які ідеї?


1
Перенесіть цей шаблонний код у допоміжний метод, і ця проблема вас більше ніколи не турбуватиме.
usr

Відповіді:


91

Справа в тому Serializable, що за замовчуванням це відбувається з часів, коли .NET навіть не випускався (до 1999 року), з програмування DTC ( Координатор розподілених транзакцій ).

DTC використовує власне перерахування ISOLATIONLEVEL :

ISOLATIONLEVEL_SERIALIZABLE Дані, прочитані поточною транзакцією, не можуть бути змінені іншою транзакцією, поки поточна транзакція не закінчиться. Не можна вставляти нові дані, які могли б вплинути на поточну транзакцію. Це найбезпечніший рівень ізоляції і є типовим, але допускає найнижчий рівень паралельності.

.NET TransactionScopeпобудований на основі цих технологій.

Тепер наступне питання: чому DTC визначає ISOLATIONLEVEL_SERIALIZABLEрівень транзакцій за замовчуванням? Припускаю, це тому, що DTC був розроблений приблизно в 1995 році (до 1999 точно). На той час стандартом SQL був SQL-92 (або SQL2).

І ось що говорить SQL-92 про рівні транзакцій:

SQL-транзакція має рівень ізоляції, який READ UNMMITTEDED, READ COMMITTED, REPEATABLE READ або SERIALIZABLE. Рівень ізоляції SQL-транзакції визначає ступінь впливу на операції з SQL-даними або схемами в цій SQL-транзакції наслідків та може впливати на операції з SQL-даними або схемами при одночасних SQL-транзакціях. Рівень ізоляції SQL-транзакції за замовчуванням СЕРІАЛІЗОВАНИЙ . Рівень може бути чітко встановлений <set transaction statement>.

Виконання одночасних SQL-транзакцій на рівні ізоляції SERIALIZABLE гарантовано може бути серіалізується. Серіалізоване виконання визначається як виконання операцій одночасного виконання SQL-транзакцій, що дає той самий ефект, що і деяке послідовне виконання тих самих SQL-транзакцій. Послідовне виконання - це таке, при якому кожна SQL-транзакція виконується до завершення до початку наступної SQL-транзакції.


51

Корисний спосіб скоротити написання зразкового коду - це обернути його у клас будівельника так:

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
}

Ви можете додати інші типові стандартні обсяги транзакцій за замовчуванням до класу конструктора, коли вони вам потрібні.


1
це насправді те саме, що я зробив, маючи центральне місце, де можна було отримати транзакцію "за замовчуванням" для моїх випадків використання
Бернхард Кірхер,

29

Що ж, я думаю, це одне з тих запитань типу "тільки дизайнер точно знав би". Але ось мої два центи так чи інакше:

Хоча серіалізація є найбільш "обмежуючим" рівнем ізоляції (щодо блокування, в RDBMS на основі блокування, і, отже, одночасного доступу, тупикових ситуацій тощо), вона також є найбільш "безпечним" рівнем ізоляції (щодо узгодженості даних).

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

Зробити його змінним за допомогою конфігурації було б поганою ідеєю, тому що, возившись з конфігурацією, ви могли б зробити ідеально робочу програму зламаною (оскільки вона може просто не призначена для роботи з чимось іншим). Або, щоб повернути аргумент, "жорстко закодувавши" рівень ізоляції, ви можете переконатися, що ваш додаток працює належним чином. Можливо, рівень ізоляції не підходить для параметра конфігурації (хоча час очікування транзакції справді є).


3
"ви могли б зробити ідеально працюючу програму для зламаної" +1
Стівен

2
Зауважте, що навіть рівень ізоляції, який можна серіалізувати, все ще не гарантує відсутність проблем із валютою.
Стівен

@ Christian.K Дякую за відповідь. Ви маєте рацію - це знає лише дизайнер. Можливо, у мене просто проблема з серіалізацією, оскільки я схильний думати про бази даних, коли чую рівень ізоляції. Серіалізація може бути хорошим замовчуванням для інших постачальників транзакцій.
Бернхард Кірхер,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.