Зачем нужны транзакции
Что проверяют
Понимаете ли вы четыре свойства и знаете ли, какие аномалии предотвращает изоляция.
Как отвечать
Транзакция объединяет несколько операций в одну логически неделимую единицу работы. Нужна везде, где изменение состоит из нескольких шагов и промежуточное состояние недопустимо: перевод денег между счетами, создание заказа с позициями и списанием остатков.
Свойства ACID:
- атомарность: выполняются либо все операции, либо ни одной. Сбой на третьем шаге откатывает первые два;
- согласованность: база переходит из корректного состояния в корректное, ограничения и внешние ключи соблюдены;
- изоляция: параллельные транзакции не видят промежуточных результатов друг друга;
- долговечность: после подтверждения данные переживут падение сервера, за это отвечает журнал предзаписи.
Про изоляцию стоит говорить через аномалии, которые она предотвращает:
- грязное чтение: увидеть неподтверждённое чужое изменение;
- неповторяемое чтение: прочитать строку дважды и получить разные значения;
- фантомы: повторный запрос по условию возвращает новые строки;
- потерянное обновление: две транзакции прочитали значение, посчитали и записали, одно изменение пропало.
Уровни изоляции задают, какие аномалии допустимы. В PostgreSQL по умолчанию «прочитанное подтверждённое», есть «повторяемое чтение» и «сериализуемый», реализованные через снимки данных. Чем строже уровень, тем больше конфликтов и откатов, поэтому его выбирают осознанно, а не по максимуму.
Практические правила: транзакция должна быть короткой, внутри неё не делают сетевых вызовов и не ждут пользователя. Для длинных сценариев берут оптимистичную блокировку по версии строки, а для операций между сервисами транзакция вообще неприменима, там сага с компенсациями.
Где спотыкаются
Называют ACID, но не могут привести пример аномалии.
Держат транзакцию открытой на время внешнего вызова.
Читают значение, считают в коде и записывают, теряя чужое обновление.
Ставят сериализуемый уровень везде и получают лавину откатов.