Какие особенности транзакций существуют
Что проверяют
Понимаете ли вы, что транзакция это не только beginTransaction() и commit(), а договор с базой о видимости данных при конкурентной работе. Следом спрашивают про уровни изоляции по умолчанию и про обработку дедлока в PHP-коде.
Как отвечать
Начните с ACID: атомарность, согласованность, изоляция, долговечность. Основное время отдайте изоляции и аномалиям:
- грязное чтение: видны незафиксированные изменения чужой транзакции, возможно только на
READ UNCOMMITTED; - неповторяемое чтение: повторный
SELECTтой же строки даёт другое значение,READ COMMITTEDего допускает; - фантомы: повторный запрос по условию возвращает новые строки;
- потерянное обновление: две транзакции читают баланс, считают новое значение в PHP и перезаписывают друг друга.
Назовите умолчания: InnoDB в MySQL работает на REPEATABLE READ, обычные чтения идут из снимка, а блокирующие защищены next-key блокировками. PostgreSQL по умолчанию на READ COMMITTED, а его SERIALIZABLE при конфликте откатывает транзакцию с SQLSTATE 40001, и её нужно повторить.
Дальше про PHP:
- PDO:
beginTransaction(),commit(),rollBack()вtry/catch,inTransaction(). С PHP 8 режим ошибок по умолчаниюPDO::ERRMODE_EXCEPTION; - фреймворки:
DB::transaction()в Laravel принимает число попыток и повторяет замыкание при дедлоке, в Doctrine естьwrapInTransaction(). Вложенность они эмулируют черезSAVEPOINT; - блокировки:
SELECT ... FOR UPDATEдля пессимистичной, колонкаversionдля оптимистичной.
Где спотыкаются
Пишут «прочитал, посчитал в PHP, записал» без FOR UPDATE и теряют обновления. Надёжнее атомарный запрос UPDATE accounts SET balance = balance - 100 WHERE id = ?.
Считают дедлок багом, который лечится таймаутом. InnoDB сама находит взаимную блокировку и откатывает одну из транзакций с ошибкой 1213, приложение должно её повторить, а блокировки лучше брать в одном порядке.
Вызывают beginTransaction() второй раз на том же соединении и получают исключение: PDO вложенных транзакций не знает. Ловушка MySQL: DDL вроде ALTER TABLE делает неявный коммит, поэтому миграция из нескольких шагов не откатывается целиком.