ACID
ACID — атомарность, согласованность, изоляция, долговечность
TL;DR
ACID — набор из четырёх свойств транзакций в СУБД: Atomicity (атомарность), Consistency (согласованность), Isolation (изолированность), Durability (долговечность). Гарантирует корректность данных даже при сбоях и параллельном доступе.
Краткое определение
ACID — аббревиатура, описывающая четыре ключевых свойства транзакционных систем: атомарность (всё или ничего), согласованность (данные в допустимом состоянии), изоляция (параллельные транзакции не мешают друг другу), долговечность (после коммита данные не теряются).
Оригинал и перевод
- Язык: английский
- Оригинал: ACID
- Расшифровка: Atomicity, Consistency, Isolation, Durability
- Буквальный перевод: атомарность, согласованность, изоляция, долговечность
- Автор термина: Андреас Рейтер (Andreas Reuter), 1983 год
Четыре свойства ACID
1️⃣ Atomicity (Атомарность)
Транзакция выполняется полностью или не выполняется вовсе.
Если любая часть транзакции падает — отменяется вся транзакция целиком.
Пример:
BEGIN TRANSACTION; -- Перевод денег между счетами UPDATE accounts SET balance = balance - 1000 WHERE id = 1; -- Снять со счёта 1 UPDATE accounts SET balance = balance + 1000 WHERE id = 2; -- Зачислить на счёт 2 -- Если второй UPDATE упадёт — первый будет отменён COMMIT;
Реализация: WAL (Write-Ahead Logging), two-phase commit
2️⃣ Consistency (Согласованность)
Транзакция переводит данные из одного допустимого состояния в другое.
Все ограничения (constraints), триггеры и правила соблюдаются.
Пример:
-- Ограничение: баланс не может быть отрицательным ALTER TABLE accounts ADD CONSTRAINT balance_non_negative CHECK (balance >= 0); -- Эта транзакция будет отклонена, если нарушит CHECK UPDATE accounts SET balance = balance - 5000 WHERE id = 1; -- ERROR: check constraint "balance_non_negative" violated
Реализация: foreign keys, unique constraints, check constraints, триггеры
3️⃣ Isolation (Изоляция)
Параллельные транзакции не влияют друг на друга.
Каждая транзакция «видит» данные так, как будто выполняется одна.
Уровни изоляции (от слабого к сильному):
| Уровень | Проблема | Чтение своих изменений |
|---|---|---|
| READ UNCOMMITTED | Dirty reads | Да |
| READ COMMITTED | Non-repeatable reads | Да |
| REPEATABLE READ | Phantom reads | Да |
| SERIALIZABLE | Нет аномалий | Да |
Пример проблемы (Dirty Read):
Транзакция A: UPDATE accounts SET balance = 100 WHERE id = 1; (ещё не COMMIT) Транзакция B: SELECT balance FROM accounts WHERE id = 1; ← Видит 100! Транзакция A: ROLLBACK; ← А данных уже нет
Реализация: MVCC (Multi-Version Concurrency Control), блокировки
4️⃣ Durability (Долговечность)
После COMMIT изменения не теряются даже при сбое.
Даже если сервер упадёт через секунду после коммита — данные сохранятся.
Пример:
BEGIN; UPDATE orders SET status = 'paid' WHERE id = 123; COMMIT; ← С этой секунды данные сохранены навсегда -- Сервер падает через 1 секунду... -- После перезапуска: status = 'paid' на месте
Реализация: WAL, fsync, репликация на диск, RAID
Где используется
- Реляционные СУБД: PostgreSQL, MySQL, MariaDB, Oracle, SQL Server
- Финансовые системы: платежи, переводы, инвойсы
- Системы учёта: склад, заказы, инвентарь
- Распределённые транзакции: двухфазный коммит (2PC)
Когда это важно
ACID критичен в следующих сценариях:
- Платежи и финансы — нельзя потерять деньги или создать дубль
- Заказы и инвентарь — согласованность остатков на складе
- Регистрация пользователей — уникальность email/username
- Аудит и логирование — данные не должны теряться
ACID в PostgreSQL vs MySQL
| Свойство | PostgreSQL | MySQL (InnoDB) |
|---|---|---|
| Atomicity | ✅ WAL, rollback | ✅ Undo logs |
| Consistency | ✅ Constraints, triggers | ✅ Foreign keys, checks |
| Isolation | ✅ MVCC, 4 уровня | ✅ MVCC, 4 уровня |
| Durability | ✅ WAL, fsync | ✅ Redo log, fsync |
По умолчанию:
- PostgreSQL:
READ COMMITTED - MySQL InnoDB:
REPEATABLE READ
CAP теорема и ACID
CAP теорема: в распределённой системе нельзя одновременно обеспечить:
- Consistency (согласованность)
- Availability (доступность)
- Partition tolerance (устойчивость к разделению)
ACID vs BASE:
| Подход | Принцип | Где используется |
|---|---|---|
| ACID | Strong consistency | Реляционные СУБД, финансы |
| BASE | Eventual consistency | NoSQL (Cassandra, DynamoDB) |
BASE: Basically Available, Soft state, Eventual consistency
Типичные ошибки
- ❌ Игнорирование уровней изоляции — по умолчанию не всегда подходит
- ❌ Длинные транзакции — блокировки держатся слишком долго
- ❌ Отсутствие индексов на foreign keys — блокировки таблиц
- ❌ N+1 запрос в транзакции — тысячи мелких запросов вместо одного
- ❌ ACID и NoSQL — ожидание ACID от систем с eventual consistency
Аналоги и связанные термины
- MVCC — Multi-Version Concurrency Control (реализация изоляции)
- WAL — Write-Ahead Logging (реализация атомарности и долговечности)
- CAP theorem — теорема о распределённых системах
- Eventual consistency — « eventual» согласованность (NoSQL)
- Two-phase commit — протокол для распределённых транзакций
Смотри также (статьи на сайте)
- PostgreSQL для веб-разработчиков — миграция с MySQL, JSON, оптимизация
- Бэкап и восстановление PostgreSQL — pg_dump и pg_restore
Смотри также (сниппеты)
- PostgreSQL: JSONB и GIN-индекс — работа с JSON в транзакциях
- Идемпотентный агент с блокировкой — защита от параллельного запуска
Смотри также (термины)
- Репликация — копирование данных между узлами
- Идемпотентность — свойство операций
- Backpressure — обратное давление в потоках
Мини-FAQ
ACID только для реляционных СУБД?
Ответ: В основном да. Некоторые NoSQL системы добавляют транзакции (MongoDB 4.0+, Google Spanner), но классический ACID — это про реляционные СУБД.
Какой уровень изоляции использовать?
Ответ:
- READ COMMITTED — по умолчанию, подходит для большинства сценариев
- REPEATABLE READ — если нужно гарантировать повторное чтение
- SERIALIZABLE — только если критична полная изоляция (снижает производительность)
ACID замедляет систему?
Ответ: Да, особенно SERIALIZABLE и SYNC коммиты. Но для финансов и критичных данных это необходимая плата за надёжность.
Можно ли отключить ACID для производительности?
Ответ: Частично:
SET synchronous_commit = off(PostgreSQL) — быстрее, но возможна потеря последних транзакцийinnodb_flush_log_at_trx_commit = 0(MySQL) — аналогично
Но это компромисс между производительностью и надёжностью.