В SQL транзакции позволяют группировать несколько операций (insert/update/delete) в единую атомарную единицу работы, которую можно либо полностью применить, либо отменить. Жизненный цикл транзакции строится на командах:
BEGIN или START TRANSACTION — начало транзакции;COMMIT — фиксация изменений;ROLLBACK — откат всех изменений внутри транзакции.SQL поддерживает уровни изоляции транзакций (Read Uncommitted, Read Committed, Repeatable Read, Serializable), которые определяют видимость данных между параллельными транзакциями и защищают от проблем, таких как "грязные чтения" или "фантомные строки".
Для контроля целостности данных необходимы грамотные:
SELECT ... FOR UPDATE).Пример на PostgreSQL:
BEGIN; -- Получаем и блокируем строку товара SELECT * FROM inventory WHERE id = 1 FOR UPDATE; UPDATE inventory SET quantity = quantity - 1 WHERE id = 1; COMMIT;
Какой уровень изоляции по умолчанию установлен в популярных СУБД (PostgreSQL, MySQL) и чем он отличается от SERIALIZABLE?
Ответ:
В PostgreSQL по умолчанию используется уровень Read Committed — в нем транзакция видит только зафиксированные на момент запроса данные, но возможны "неповторяющиеся чтения" (non-repeatable reads).
В MySQL (InnoDB) — Repeatable Read. Отличие от Serializable в том, что только последний полностью предотвращает любые фантомные или параллельные изменения, но работает заметно медленнее из-за глобальных блокировок.
Пример:
-- В Repeatable Read SELECT может вернуть те же строки, а в Read Committed — могут появиться новые между двумя SELECT внутри транзакции.
История
В крупной финансовой системе во время массовых переводов между счетами при низком уровне изоляции (Read Committed) периодически возникали ситуации, когда один и тот же баланс использовался одновременно несколькими транзакциями. Это приводило к двойному расходованию средств (race condition). После перехода на
Serializableи грамотное управление блокировками проблема исчезла.
История
В электронной коммерции транзакция с
UPDATE product SET stock = stock - 1без обертывания в транзакцию приводила к продаже больше товара, чем есть на складе. Проблема выявилась только при большом количестве конкурирующих заказов. Решение — использовать транзакции и блокировку строк черезSELECT ... FOR UPDATE.
История
В логистической системе в одной из таблиц при частых обновлениях забыли о явном коммите. В случае сбоев часть данных терялась из-за автокоммита или некорректного rollback. Итог — потеря записей и дорогостоящий аудит.