И снова всем привет)
Продолжаем линейку постов про транзакции.
🔧 Транзакции в MySQL: нюансы▶️ MySQL / InnoDB
Если хочешь, чтобы транзакции работали как надо, таблицы должны быть в InnoDB.
Почему:
- построчные блокировки, а не блокировка всей таблицы
- поддержка внешних ключей
- нормальная атомарность и откаты
- корректная работа уровней изоляции
MyISAM — не подходит, он использует устаревший движок без поддержки транзакций, использующий блокировки всей таблицы.
В продакшене его применение создаёт серьёзные ограничения и повышает риски некорректной работы с данными.
▶️ Уровень изоляции
В MySQL (InnoDB) уровень изоляции по умолчанию — REPEATABLE READ.
Он обеспечивает работу транзакции со стабильным снимком данных: все повторные SELECT внутри одной транзакции возвращают одну и ту же версию строк, даже если параллельные транзакции их уже изменили.
❗️Каждый уровень изоляции определяет, какие аномалии конкурентного доступа возможны:
- Dirty reads — чтение незакоммиченных данных другой транзакции.
- Non-repeatable reads — одна и та же строка возвращает разные значения в рамках одной транзакции.
- Phantom reads — при повторном запросе появляются новые строки, которых не было в первой выборке.
В InnoDB dirty reads исключены автоматически (READ UNCOMMITTED фактически не используется).
REPEATABLE READ блокирует non-repeatable reads, но фантомы сохраняются, что на нагруженных системах может приводить к гонкам в логике проверки и вставки данных.
При необходимости максимально строгой модели используют SERIALIZABLE.
Этот уровень устраняет фантомы, но делает все операции чтения потенциально блокирующими, что резко снижает производительность.
Поэтому его применяют точечно, только там, где фантомы действительно критичны для корректности
▶️ DDL и транзакции: почему MySQL делает implicit commit
В MySQL операции изменения структуры данных (DDL) автоматически вызывают commit до и после выполнения.
Этот механизм встроен в движок и не зависит ни от приложения, ни от фреймворка.
Какие команды вызывают implicit commit:
- CREATE TABLE
- ALTER TABLE
- DROP TABLE / DROP INDEX
- TRUNCATE
- RENAME TABLE
- CREATE/DROP VIEW
- SET AUTOCOMMIT = 1
Как только выполняется любая из этих команд:
1.MySQL выполняет скрытый commit текущей транзакции.
2.Выполняет DDL.
3.Делает ещё один скрытый commit после DDL.
Это означает, что откатить изменения, выполненные до DDL, невозможно — они уже зафиксированы.
Пример сценария:
1. START TRANSACTION;
2. Вставляем данные.
3. Выполняем ALTER TABLE.
4. MySQL автоматически коммитит всё, что было до команды.
5. Попытка ROLLBACK уже не влияет на вставленные данные.
Это критичное поведение, которое разработчик обязан учитывать.
Laravel или любой ORM не могут перехватить или отменить implicit commit, потому что решение принимает сам MySQL на уровне протокола.
⚠️Последствия использования DDL внутри бизнес-операций:
- невозможность гарантировать атомарность операций
- риск частично записанных данных
- неконтролируемые состояния при сбоях
- нарушение инвариантов бизнес-логики
Поэтому DDL строго отделяют от обычных транзакций:
- применяют только через миграции
- выполняют в отдельные деплой-этапы
- не допускают вызовов в runtime
Это базовое правило эксплуатации MySQL в продакшене.
#transactions #db #development #webdev #mysql #DDL #innoDB
Post #1478
216
- 🔥 1