Внимание! TransactionScope по умолчанию включает Serializable.

Базы данных  /  Внезапно dotNET  /  CSharp

Сегодня о TransactionScope, уровне изоляции транзакций Serializable и дырявых абстракциях.

Вообще говоря, я раньше много раз сталкивался с распределёнными транзакциями. В какой-то момент я окончательно сформировал своё мнение по этой теме. Получилось что-то вроде: “хватит, я не буду их использовать вообще, разве что в ход со стороны оппонента пойдут огнестрельное оружие и прочие нечестные аргументы”.

По этой причине моё знакомство с TransactionScope свелось к его использованию в интеграционных тестах (без распределённой составляющей, просто для удобного отката транзакций) и редким спорам с коллегами. Но сегодня, внезапно…

Разговор на работе

Вообще говоря, в появлении этого текста на свет основная заслуга Макса (@force_net). С ним сегодня сначала говорили про Snapshot Isolation, потом перешли на TransactionScope. И говорит Макс — “там ведь Serializable по умолчанию”.
Я говорю — “да ладно, нелогично же — без него Read Committed по умолчанию”. Так, слово за слово, решили проверить.

Лирическое отступление

На случай, если вы мало сталкивались с БД, про уровни изоляции есть вполне сносная, хотя не всем с первого раза понятная документация. Поэтому лучше дам ссылку на общее описание от википедии.

Если вкратце, применимость Serializable в web-приложениях не очень высокая — слишком много блокировок. Когда мы с Максом обсуждали эти особенности, он привёл пример “то есть если один заказывает билеты на фильм, то блокируются на всякий случай все места, а второй будет ждать…” “… пока фильм не выложат на торрентах выйдет на DVD”, продолжил я :)

Постараюсь чуть позже написать более подробную статью на тему уровней изоляции.

Результаты проверки

Как я уже говорил, TransactionScope пользовался давно и редко. Поэтому я несколько удивился, увидев подтверждение упомянутому феномену. Сказал я Максу что-то вроде — “с чего-бы высокомудрые архитекторы и разработчики такой нетрадиционный способ обратной совместимости выбрали?”.

А он в меня ссылкой кидает. Ладно, теперь понятны хотя бы предпосылки этого не самого логичного решения — предпочли выбрать поведение по умолчанию как в MS DTC, а не как в MS SQL и System.Data.SqlClient. Но, чёрт возьми, почему я не вижу рядом с названием класса слов “по умолчанию использует уровень изоляции Serializable” большими красными буквами? В документации класса вообще Serializable не упомянули :(

Выводы

Если вы подсели на “синтаксическое сладкое”, любите async/await (предпочитая не погружаться в детали его работы) и используете TransactionScope из коробки в production — ваше дело. Я больше скажу, даже MS DTC вы можете использовать из приложения в ASP.NET. Да хоть мигающий фиолетовый текст на жёлтом фоне. Кто я такой, чтобы вам указывать? :)

Однако, подумайте над переопределением уровня изоляции транзакций для TransactionScope. Разумеется, я согласен, что для каких-то решений Serializable будет правильным выбором. Главное, чтобы выбор был осознанным…

Базы данных  /  Внезапно dotNET  /  CSharp