Тест на вакансию

Как MySQL реализует поддержку ACID

1 июля 2025 г.
258
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 через:
  1. Undo Log → Atomicity.
  2. Ограничения БД → Consistency.
  3. MVCC + уровни изоляции → Isolation.
  4. Redo Log → Durability.
Это делает MySQL надежным выбором для финансовых систем, интернет-магазинов и других ACID-критичных приложений.
Поделиться: