ROLLBACK в MySQL: граница транзакции важнее соседних строк кода

2 мин чтения

Проверяем откат изменений InnoDB и разбираем, почему команды DDL могут нарушить ожидаемые границы транзакции.

Откат работает в границах транзакции
  1. START TRANSACTIONНачинаем группу изменений данных
  2. Два UPDATEВыполняем связанные изменения без DDL
  3. ROLLBACKОтменяем незавершённые изменения транзакции

Нужно списать сумму с одной записи и прибавить к другой. Если второе изменение не удалось, первое тоже должно отмениться. Для InnoDB это обычная задача транзакции, но одного START TRANSACTION недостаточно: некоторые команды сами вызывают фиксацию. Проверим ROLLBACK на двух обновлениях и разберём, что лучше вынести за их пределы.

Создаём объекты до начала операции

CREATE TABLE demo_wallets (
    id integer PRIMARY KEY,
    amount integer NOT NULL
) ENGINE=InnoDB;
INSERT INTO demo_wallets VALUES (1, 100), (2, 100);
START TRANSACTION;
UPDATE demo_wallets SET amount = amount - 10 WHERE id = 1;
UPDATE demo_wallets SET amount = amount + 10 WHERE id = 2;
SELECT * FROM demo_wallets ORDER BY id;
ROLLBACK;
SELECT * FROM demo_wallets ORDER BY id;

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

Кто отвечает за откат при ошибке

Код обработки исключения должен явно решить судьбу транзакции. Нельзя предполагать, что любой отказ одного выражения автоматически отменяет все ранее успешные выражения. Для обычной ошибки команды такой вывод часто неверен. При выходе из неуспешного сценария приложение должно выполнить корректный откат и вернуть соединение в известном состоянии. В контрольном опыте намеренно вызовите ошибку второго обновления и проверьте состояние после обработки исключения. Такая проверка обнаруживает частично сохранённую операцию раньше пользовательского обращения.

Изменение структуры — отдельный процесс

Многие команды DDL, включая обычные CREATE TABLE и ALTER TABLE, вызывают неявную фиксацию. Если вставить такую команду между обновлениями, последующий ROLLBACK может не вернуть состояние к моменту START TRANSACTION. Поэтому подготовку схемы в примере выполняют заранее. Проверка этого свойства должна проходить на одноразовых данных с ясным ожиданием результата.

Перед переносом проверьте движки таблиц через SHOW CREATE TABLE: нетранзакционные объекты меняют возможности отката. Для пула важны также autocommit и незавершённая работа прежнего запроса. Проверьте три исхода — COMMIT, ROLLBACK и исключение между обновлениями — и сравните сохранённые значения с ожидаемыми.

Источники и дальнейшее чтение