Вступление
В стандарте SQL описывается четыре уровня изоляции транзакций — Read uncommited (Чтение незафиксированных данных), Read committed (Чтение зафиксированных данных), Repeatable read (Повторяемое чтение) и Serializable (Сериализуемость). В данной статье будет рассмотрен жизненный цикл четырёх параллельно выполняющихся транзакций с уровнями изоляции Read committed и Serializable.
Для уровня изоляции Read committed допустимы следующие особые условия чтения данных:
Неповторяемое чтение — транзакция повторно читает те же данные, что и раньше, и обнаруживает, что они были изменены другой транзакцией (которая завершилась после первого чтения).
Фантомное чтение — транзакция повторно выполняет запрос, возвращающий набор строк для некоторого условия, и обнаруживает, что набор строк, удовлетворяющих условию, изменился из-за транзакции, завершившейся за это время.
Что же касается Serializable, то данный уровень изоляции самый строгий, и не имеет феноменов чтения данных.
ACID или 4 свойства транзакций
Прежде чем приступим к рассмотрению уровней изоляции транзакции в паре слов вспомним об основных требованиях к транзакционной системе.
Atomicity (атомарность) — выражается в том, что транзакция должна быть выполнена в целом или не выполнена вовсе.
Consistency (согласованность) — гарантирует, что по мере выполнения транзакций, данные переходят из одного согласованного состояния в другое, то есть транзакция не может разрушить взаимной согласованности данных.
Isolation (изолированность) — локализация пользовательских процессов означает, что конкурирующие за доступ к БД транзакции физически обрабатываются последовательно, изолированно друг от друга, но для пользователей это выглядит, как будто они выполняются параллельно.
Durability (долговечность) — устойчивость к ошибкам — если транзакция завершена успешно, то те изменения в данных, которые были ею произведены, не могут быть потеряны ни при каких обстоятельствах.
Уровень изоляции Read Committed
По умолчанию в PostgreSQL уровень изоляции Read Committed. Такой уровень изоляции всегда позволяет видеть изменения внесённые успешно завершёнными транзакциями в оставшихся параллельно открытых транзакциях. В транзакции, работающей на этом уровне, запрос SELECT (без предложения FOR UPDATE/SHARE) видит только те данные, которые были зафиксированы до начала запроса; он никогда не увидит незафиксированных данных или изменений, внесённых в процессе выполнения запроса параллельными транзакциями. По сути запрос SELECT видит снимок базы данных в момент начала выполнения запроса. Однако SELECT видит результаты изменений, внесённых ранее в этой же транзакции, даже если они ещё не зафиксированы. Также заметьте, что два последовательных оператора SELECT могут видеть разные данные даже в рамках одной транзакции, если какие-то другие транзакции зафиксируют изменения после выполнения первого SELECT.
Суть уровня изоляции Read Committed показана на диаграмме 1.
Примечание: В таблице уже находится запись с первой версией данных (v1). Прошу воспринимать команды SELECT v1; — как команду возвращающую данные версии v1, а UPDATE v1 to v2; — как команду обновления данных с первой версии до второй.
Примечание. На диаграмме не показано действие запроса INSERT. В рамках данного уровня изоляции, строки добавленные, например в шаге 3, в Первой транзакции, были бы ВИДНЫ остальным транзакциям после завершения Первой транзакции.
Частичная изоляция транзакций, обеспечиваемая в режиме Read Committed, приемлема для множества приложений. Этот режим быстр и прост в использовании, однако он подходит не для всех случаев. Приложениям, выполняющим сложные запросы и изменения, могут потребоваться более строго согласованное представление данных, например Serializable.
Уровень изоляции Serializable
Изоляция уровня Serializable обеспечивает беспрепятственный доступ к базе данных транзакциям с SELECT запросами. Но для транзакций с запросами UPDATE и DELETE, уровень изоляции Serializable не допускает модификации одной и той же строки в рамках разных транзакций. При изоляции такого уровня все транзакции обрабатываются так, как будто они все запущены последовательно (одна за другой). Если две одновременные транзакции попытаются обновить одну и туже строку, то это будет не возможно. В таком случае PostgreSQL принудит транзакцию, вторую, да и все последующие, что пытались изменить строку к отмене (откату — ROLLBACK).
Суть уровня изоляции Serializable показана на диаграмме 2.
Примечание. На диаграмме не показано действие запроса INSERT. В рамках данного уровня изоляции, строки добавленные, например в шаге 3, в Первой транзакции, были бы НЕ ДОСТУПНЫ Второй, Третьей и Четвёртой транзакциям после завершения Первой транзакции. Также на диаграмме не показан результат ROLLBACK (Шаги 8 и 11). В случае если бы Вторая и Третья транзакции делали какие либо изменения над не заблокированными данными, то все эти изменения не были бы зафиксированы, так как транзакции завершаются неудачно (суть свойства — Atomicity).
Уровень изоляции Serializable гарантирует, что все затронутые в транзакции данные не будут изменены другими транзакциями. На этом уровне появление "фантомов" исключается, поэтому становятся возможными сложные конкурентные операции. На практике такой уровень изоляции требуется в учетных системах.
Для транзакций содержащих только SELECT запросы, использование уровня изоляции Serializable оправдывает себя тогда, когда вы не хотите видеть внесённые изменения параллельно завершёнными транзакциями в ходе работы текущей транзакции.
Аномалия сериализации (Потерянное обновление)
Ещё один феномен чтения данных, описывается тем, что результат успешной фиксации группы транзакций оказывается несогласованным при всевозможных вариантах исполнения этих транзакций по очереди.
Сориентируйте, пожалуйста, меня в комментариях, если я заблуждаюсь насчёт того, что аномалия сериализации и потерянное обновление связанные между собой феномены.
Документация на сайте PostgreSQL PRO пишет, что Read Committed допускает «Serialization Anomaly». Отечественная Wikipedia, не настаивая на то, что таблица относится именно к PostgreSQL, пишет, что Read Commited предотвращает аномалию сериализации. Английская Википедиа о таком феномене чтения данных умалчивает. Но немецкая Википедия приводит в своей версии таблицы феномен «Lost Updates», указывая на то, что Read Committed может быть не подвержен потере обновлений с дополнительной защитой через курсор (Cursor Stability). Украинская Википедия поддерживает русскоязычную версию статьи, испанская Википедия поддерживает английскую версию статьи. Англоязычная документация по PostgreSQL не отличается от документации с сайта PostgreSQL PRO.
Cursor Stability расширяет блокировочное поведение уровня READ COMMITED для SQL-курсоров, добавляя новую операцию чтения (Fetch) по курсору rc (означает read cursor, т.е. чтение по курсору) и требуя, чтобы блокировка устанавливалась на текущем элементе курсора. Блокировка удерживается до тех пор, пока курсор не будет перемещен (пока не измениться его текущий элемент) или закрыт, возможно, операцией фиксации. Естественно, транзакция, читающая по курсору, может изменить текущую строку (wc – запись по курсору), и в этом случае блокировка по записи этой строки будет сохраняться до тех пор, пока транзакция не зафиксируется, даже после передвижения курсора с последующей выборкой следующей строки.
Итог: 149.
Заключение
Понимание уровней изоляции транзакций является важным аспектом при обработке данных в любой многопользовательской СУБД. Уровни изоляции обладают четко определенными характеристиками и поведением. Более высокие уровни изоляции уменьшают возможности параллельной обработки данных и повышают риск взаимной блокировки процессов. Поэтому корректное использование уровней в зависимости от задач приложений всегда является выбором разработчика в зависимости от требований к обеспечению логической целостности данных, к скорости и к возможности параллельной многопользовательской обработки.
Литература
» MVCC Unmasked
» 13.2. Изоляция транзакций
» Критика уровней изолированности
» Уровни изоляции транзакций в SQL. Шпаргалка
» Уровень изолированности транзакций
» … the lost update phenomena
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (18)
gturk
23.12.2016 08:22+2Для полноты картины еще не хватает описания какие дедлоки возникают в различных комбинация уровней изоляции.
sfsiarhei
23.12.2016 09:35спасибо
можно ли подробнее узнать про шаг7 первого примера? Имею ввиду блокировки данныхFolklore
23.12.2016 09:37Вот этому я посвятил отдельный параграф «Аномалия сериализации (Потерянное обновление)». Как я разобрался, данная блокировка происходит для предотвращения потери обновлений. Но официальная документация Постгреса пишет о том, что Read Committed подвержен аномалии сериализации. Либо я не правильно соотношу эти два феномена чтения данных, и «Аномалия сериализации» это не «Потерянное обновление». Либо документация ошибается (это я пишу с осторожностью), и Read Committed в Постгресе дополнительно защищен через курсор (Cursor Stability), что и создаёт блокировку в Шаге 6 на обновление данных для других транзакций.
zhekappp
23.12.2016 10:12Надо будет в oracle попробовать. Для read comitted там все также будет, а, вот, для serializable — не уверен.
CDuke
23.12.2016 11:16В Oracle Serializable это на самом деле Snapshot Isolation.
zhekappp
23.12.2016 12:00Т.е., теоретичски, не должно быть ошибок и rollback, а просто будем дольше ждать в этом сценарии?
DmitryKuzmenko
27.12.2016 14:03snapshot — это repeatable read. Автор статьи как-то прыгнул от read committed к serializable мимо repeatable read.
vlivyur
27.12.2016 17:23Т.е. фантомные чтения возможны? В вики говорят что в оракле вообще repeatable read отсутствует.
DmitryKuzmenko
27.12.2016 19:03Это стандарт кривой, не имеет уровня snapshot, который строже repeatable read, без фантомных чтений, но слабее serializable. Поэтому если СУБД имеет что-то вроде repeatable read, его и упоминают. А snapshot там или нет, это уже дело десятое. Реального repeatable read, чтобы с фантомами, по-моему нигде нет, кроме db2.
DmitryKuzmenko
27.12.2016 19:05до кучи — Критика уровней изолированности стандарта ANSI SQL
http://citforum.ru/database/classics/SQL_critiques/
оригинал 1995 года.
Varim
23.12.2016 14:25У вас картинки не показываются
https://dl.dropboxusercontent.com/u/37142115/blog/production/posts/2/read_committed/0.png
Error (429)
This account's links are generating too much traffic and have been temporarily disabled!
vanburg
Вот это очень ценная шпора, спасибо!
Не часто требуется что-то экзотическое использовать и приходится в доку лезть, а она немного дубовая. Тут все в одном месте, и наглядно.
Slider123
Поддерживаю! Очень крутое раскрытие информации! Спасибо!