Транзакция — это набор действий с данными, объединенный в логическую единицу. Она либо выполняется целиком, либо нет. Классический пример с операцией перевода денег со счета на счет:

Начать транзакцию

прочесть баланс на счету номер 5

уменьшить баланс на 10 денежных единиц

сохранить новый баланс счёта номер 5

прочесть баланс на счету номер 7

увеличить баланс на 10 денежных единиц

сохранить новый баланс счёта номер 7

Окончить транзакцию

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

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

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

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

Грязное чтение
Когда читаются данные, которые в этот момент изменяются транзакцией, а потом транзакция откатывается и данные исчезают.

Неповторяющееся чтение
Когда несколько раз читаются данные, которые в этот момент изменяются транзакцией — каждый раз данные могут отказаться другими.

Фантомное чтение
Одна транзакция в ходе своего выполнения несколько раз выбирает множество строк по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет или удаляет строки или изменяет столбцы некоторых строк, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества строк.

Изоляция транзакций

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

Чтение неподтверждённых данных (read uncommitted)
Самый низкий уровень изоляции. Можно свободно читать незафиксированные изменения других транзакций, но запись идет строго последовательно. Таким образом, исключается только проблема потерянных обновлений: гарантируется, что в итоге в ячейку запишут нужное значение все транзакции по очереди.

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

Чтение подтверждённых данных (read committed)
Можно свободно читать все изменения своей транзакции и зафиксированные изменения чужих транзакций. Исключаются потерянные обновления и грязное чтение, остаются проблемы неповторяемых чтений и фантомов.

Повторяемое чтение (repeatable read)
Можно читать все изменения только своей транзации. Данные, измененные другими транзакциями, недоступны. Остается только проблема фантомных чтений.

Сериализуемый (serializable)
Транзакции полностью изолируются друг от друга, каждая выполняется так, как будто параллельных транзакций не существует.

ACID

Это набор из четырех требований к транзакционной системе, обеспечивающих максимально надежную и предсказуемую работу. Не все базы данных полностью реализуют ACID.

Атомарность (atomicity)
Атомарность гарантирует, что каждая транзакция будет выполнена полностью или не будет выполнена совсем. Не допускаются промежуточные состояния.

Согласованность (consistency)
Согласованность — это требование, подразумевающее, что в результате работы транзакции данные будут допустимыми. Это вопрос не технологии, а бизнес-логики: например, если количество денег на счете не может быть отрицательным, логика транзакции должна проверять, не выйдет ли в результате отрицательных значений.

Изолированность (isolation)
Гарантия того, что параллельные транзакции не будут оказывать влияния на результат других транзакций. Мы разобрались с изоляцией выше.

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

CAP-теорема

Она гласит, что в распределенной системе можно обеспечить только два свойства из трех: согласованность, доступность и устойчивость к разделению. Помогает понимать, как конкретная распределенная система будет работать и чего от нее ожидать.

Согласованность данных (consistency)
Когда во всех узлах в каждый момент времени данные согласованы друг с другом, то есть не противоречат друг другу. Если в одном из узлов в ячейке базы данных есть данные, такие же данные есть на всех остальных узлах.

Доступность (availability)
Когда любой запрос может быть обработан системой, вне зависимости от ее состояния.

Устойчивость к разделению (partition tolerance)
Когда расщепление системы на несколько изолированных секций не приводит к некорректному отклику от каждой из секций: отвалилась сеть между двумя узлами, но каждый из них может корректно отвечать своим клиентам.

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

Источник

By Ruslan Novikov

Интернет-предприниматель. Фулстек разработчик. Маркетолог. Наставник.