Транзакции и ACID
Транзакция объединяет операции в одну логическую единицу. Она заканчивается COMMIT или ROLLBACK; при ошибке внутри транзакции приложение должно знать, можно ли продолжать, откатывать до savepoint или откатывать все.
BEGIN;
UPDATE orders
SET state = 'PAID'
WHERE id = 42
AND state = 'NEW';
INSERT INTO payment_events (order_id, event_type)
VALUES (42, 'ORDER_PAID');
COMMIT;Проверка старого состояния в UPDATE важна: транзакция атомарна, но это не делает бизнес-переход корректным автоматически.
Atomicity — атомарность
Операции транзакции либо фиксируются вместе, либо их эффект отменяется. Если процесс или СУБД падает, восстановление не должно оставлять в зафиксированном состоянии только половину транзакции.
Атомарность сама по себе не определяет, что параллельная транзакция может
увидеть до commit. Это задача изоляции: например, уровень READ UNCOMMITTED
может разрешить наблюдение незавершённых изменений. Атомарность обеспечивается
механизмами журнала, отмены/версий и восстановления конкретной СУБД.
Она не распространяется автоматически на HTTP-вызов, Kafka и файловую систему. Для согласования БД с внешним миром применяют outbox, идемпотентность и компенсации.
Consistency — согласованность
Транзакция переводит БД из одного допустимого состояния в другое. Часть правил обеспечивает база (NOT NULL, CHECK, UNIQUE, FOREIGN KEY), часть остается в доменной логике.
ACID не означает, что ошибочная бизнес-логика станет правильной: база успешно зафиксирует две логически неверные операции, если они не нарушают ограничений.
Isolation — изоляция
Параллельные транзакции не должны наблюдать недопустимые промежуточные эффекты друг друга. Уровень изоляции определяет, какие аномалии разрешены и какой ценой они предотвращаются.
Изоляция — не обязательно глобальная очередь. СУБД используют MVCC, блокировки, проверку конфликтов и сериализацию. Подробнее: Изоляция транзакций.
Durability — долговечность
После подтвержденного commit данные должны пережить предусмотренные моделью отказов сбои. Обычно это связано с журналом предзаписи, сбросом на устойчивое хранилище и репликацией.
Гарантия зависит от конфигурации: асинхронная репликация, отключенный fsync или раннее подтверждение меняют окно потери данных.
Граница транзакции
Граница должна охватывать одну бизнес-операцию, но не удерживать ресурсы дольше необходимого:
- не делать медленный сетевой вызов под блокировкой без явной причины;
- не отдавать наружу успех до гарантии нужного commit;
- учитывать rollback-only и правила отката фреймворка;
- повторять транзакцию только если операция идемпотентна и ошибка допускает retry.
Связано: Ограничения, constraints, Lost Update, Опасности использования read committed, Transactional.
Вопросы
Обеспечивает ли транзакция согласованность между БД и Kafka? Нет. Нужен отдельный протокол, например transactional outbox.
Означает ли serializable последовательное физическое выполнение? Нет. Результат должен быть эквивалентен некоторому последовательному порядку; транзакции могут работать параллельно и конфликтовать при commit.
Может ли commit завершиться, а клиент получить ошибку? Да, например при потере соединения после фиксации. Поэтому повтор команды должен учитывать неопределенный исход.
Кто отвечает за Consistency? И ограничения БД, и корректная бизнес-логика.
Всегда ли durability равна «данные никогда не потеряются»? Нет, гарантия ограничена моделью отказов и настройками хранения/репликации.