1 июля 2025 г.
MySQL (особенно с движком
InnoDB) полностью соответствует требованиям ACID. Разберём, как именно обеспечивается каждое из свойств.
Atomicity (Атомарность)
Транзакция выполняется
целиком или откатывается.
Как реализовано:
- Используется журнал транзакций (Undo Log).
- Перед изменением данных MySQL сохраняет их исходное состояние в `UNDO_LOG`.
- Если транзакция прерывается, изменения откатываются из этого журнала.
Пример:
START TRANSACTION;
UPDATE accounts SET balance = balance - 1000 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE user_id = 2;
-- Если здесь произойдёт сбой, все изменения откатятся
COMMIT;
Consistency (Согласованность)
Данные всегда соответствуют
правилам БД (ограничениям, уникальности и т.д.).
Как реализовано:
- Проверка ограничений (PRIMARY KEY, FOREIGN KEY, CHECK).
- Если транзакция нарушает правила — она откатывается.
Пример:
CREATE TABLE users (
id INT PRIMARY KEY,
balance INT CHECK (balance >= 0) -- Баланс не может быть отрицательным
);
-- Если попытаться сделать баланс отрицательным, транзакция откатится:
UPDATE users SET balance = -100 WHERE id = 1;
-- Ошибка!
Isolation (Изолированность)
Параллельные транзакции
не мешают друг другу.
Как реализовано:
- Уровни изоляции (настраиваются для баланса между производительностью и строгостью):
- `READ UNCOMMITTED` (грязное чтение) — нет изоляции.
- `READ COMMITTED` — видны только завершённые изменения.
- `REPEATABLE READ` (по умолчанию в InnoDB) — гарантирует, что данные не изменятся во время транзакции.
- `SERIALIZABLE` — полная изоляция (как последовательное выполнение).
- Механизм MVCC (Multiversion Concurrency Control):
- Каждая транзакция видит **снимок данных (snapshot)** на момент своего начала.
- Изменения других транзакций становятся видны только после `COMMIT`.
Пример проблемы без изоляции:
-- Транзакция 1:
START TRANSACTION;
SELECT balance FROM accounts WHERE user_id = 1;
-- Читает 1000 ₽
-- Транзакция 2 (параллельно):
START TRANSACTION;
UPDATE accounts SET balance = 2000 WHERE user_id = 1;
COMMIT;
-- Транзакция 1 снова читает:
SELECT balance FROM accounts WHERE user_id = 1;
-- Без изоляции увидела бы 2000 ₽
-- Но при REPEATABLE READ увидит 1000 ₽ (как при старте транзакции)!
Durability (Долговечность)
После `COMMIT` данные
не потеряются даже при сбое.
Как реализовано:
- Журнал упреждающей записи (WAL — Write-Ahead Log).
- Изменения сначала записываются в `redo log` (журнал), а только потом — в таблицы.
- Даже при аварийном отключении данные можно восстановить из `redo log`.
- Настройки `innodb_flush_log_at_trx_commit`:
- `=1` (по умолчанию) — гарантирует запись `redo log` на диск при каждом `COMMIT`.
- `=0` или `=2` — меньше надёжности, но выше производительность.
Дополнительные механизмы InnoDB
- Блокировки строк (вместо блокировки всей таблицы).
- Автоматическое обнаружение взаимоблокировок (deadlocks)** + откат одной из транзакций.
- Оптимистичные и пессимистичные блокировки (SELECT ... FOR UPDATE).
Как проверить ACID в MySQL?
Убедитесь, что используете InnoDB (
MyISAM не поддерживает ACID!):
SHOW ENGINES;
Проверьте уровень изоляции:
SELECT @@transaction_isolation; -- Должно быть REPEATABLE READ
Протестируйте откат транзакции:
START TRANSACTION;
INSERT INTO test VALUES (1);
ROLLBACK; -- Данные не должны сохраниться
Вывод
MySQL (с InnoDB) реализует ACID через:
- Undo Log → Atomicity.
- Ограничения БД → Consistency.
- MVCC + уровни изоляции → Isolation.
- Redo Log → Durability.
Это делает MySQL надежным выбором для
финансовых систем, интернет-магазинов и других ACID-критичных приложений.