# Транзакция и ACID

> Транзакция — группа операций с базой данных, выполняемая как единое целое; ACID — четыре свойства (атомарность, согласованность, изоляция, долговечность), которые она гарантирует.

Источник: https://llmdocs.ru/wiki/transaction-acid/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Расшифровка**: Atomicity, Consistency, Isolation, Durability
- **Концепция транзакции**: Джим Грей (1981)
- **Термин ACID**: Тео Хэрдер, Андреас Ройтер (1983)
- **Команды SQL**: BEGIN, COMMIT, ROLLBACK, SAVEPOINT
- **Механизмы**: журнал упреждающей записи (WAL), блокировки, MVCC
- **Противопоставляется**: BASE (в распределённых NoSQL-системах)
**Транзакция** — последовательность операций с базой данных, которая выполняется как одно неделимое целое: либо применяются все изменения, либо ни одного. **ACID** — аббревиатура четырёх свойств, которые традиционно гарантирует транзакция в [реляционных СУБД](https://llmdocs.ru/wiki/relational-database.md): **атомарность** (*Atomicity*), **согласованность** (*Consistency*), **изоляция** (*Isolation*) и **долговечность** (*Durability*).

Классический пример — перевод денег: списание с одного счёта и зачисление на другой должны произойти вместе. Если сервер упадёт между двумя операциями, деньги не должны исчезнуть или появиться из ниоткуда.

## История

Понятие транзакции как единицы работы с гарантиями восстановления сформулировал Джим Грей в статье 1981 года;[6] за работы в этой области он получил премию Тьюринга (1998). Аббревиатуру ACID ввели Тео Хэрдер и Андреас Ройтер в обзоре 1983 года, посвящённом восстановлению баз данных после сбоев.[1]

## Пример

```sql
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- если что-то пошло не так: ROLLBACK;
COMMIT;
```

Пока транзакция не зафиксирована (`COMMIT`), другие сеансы не видят промежуточного состояния, а при ошибке или явном `ROLLBACK` база возвращается к исходному состоянию.[2] Точка сохранения (`SAVEPOINT`) позволяет откатить только часть транзакции.

В приложениях транзакции обычно открывают через драйвер или [ORM](https://llmdocs.ru/wiki/orm.md):

```python
with conn:                      # psycopg: COMMIT при успехе, ROLLBACK при исключении
    with conn.cursor() as cur:
        cur.execute("UPDATE accounts SET balance = balance - %s WHERE id = %s", (100, 1))
        cur.execute("UPDATE accounts SET balance = balance + %s WHERE id = %s", (100, 2))
```

## Четыре свойства

### Атомарность

Транзакция выполняется полностью или не выполняется вовсе. Если на середине возникла ошибка — нарушено ограничение, кончилось место, пропало питание, — все уже сделанные изменения отменяются. Приложению не нужно вручную «подчищать» частично записанные данные.

### Согласованность

Транзакция переводит базу из одного корректного состояния в другое: после фиксации выполняются все объявленные ограничения — типы, `NOT NULL`, `UNIQUE`, `CHECK`, внешние ключи. Эта буква отличается от остальных: база проверяет только те правила, которые ей описаны, а бизнес-логику («баланс не может быть отрицательным») поддерживает приложение, в том числе с помощью ограничений `CHECK`.

### Изоляция

Параллельные транзакции не должны мешать друг другу: результат должен быть таким, как если бы они выполнялись по очереди. Полная изоляция (сериализуемость) дорога, поэтому стандарт [SQL](https://llmdocs.ru/wiki/sql.md) определяет несколько [уровней изоляции](https://llmdocs.ru/wiki/isolation-levels.md), на которых допускаются те или иные аномалии:[3]

| Уровень | Грязное чтение | Неповторяющееся чтение | Фантомы |
|---|---|---|---|
| Read Uncommitted | возможно | возможно | возможны |
| Read Committed | нет | возможно | возможны |
| Repeatable Read | нет | нет | возможны |
| Serializable | нет | нет | нет |

Это требования-минимумы стандарта; конкретные СУБД часто дают больше. В [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) уровень по умолчанию — Read Committed, а изоляция реализована через [MVCC](https://llmdocs.ru/wiki/mvcc.md): каждая транзакция видит снимок данных, и читатели не блокируют писателей.

### Долговечность

После успешного `COMMIT` изменения не пропадут даже при внезапном отключении питания. Обычно это обеспечивает **журнал упреждающей записи** (WAL): описание изменения сначала надёжно записывается на диск в журнал (с вызовом `fsync`), и только потом СУБД сообщает об успехе. После сбоя база воспроизводит журнал и восстанавливает зафиксированные транзакции.[4] SQLite использует для той же цели журнал отката или WAL-режим.[5]

## Типичные проблемы

- **Взаимоблокировки** (*deadlock*): две транзакции ждут блокировки, удерживаемые друг другом. СУБД обнаруживает цикл и прерывает одну из них — приложение должно уметь повторить транзакцию.
- **Ошибки сериализации** на уровне Serializable — тоже сигнал к повтору, а не к аварии.
- **Долгие транзакции** удерживают блокировки и мешают очистке старых версий строк; транзакции стоит держать короткими и не ждать внутри них ответа пользователя или внешнего API.
- **Потерянное обновление**: «прочитать — изменить в коде — записать» без блокировки (`SELECT ... FOR UPDATE`) или атомарного `UPDATE ... SET x = x + 1` теряет параллельные изменения.

## ACID и распределённые системы

Обеспечить ACID на одном сервере относительно просто; в распределённой базе это требует протоколов согласования (двухфазная фиксация, консенсус Raft или Paxos) и добавляет задержки. Поэтому многие системы [NoSQL](https://llmdocs.ru/wiki/nosql.md) исторически выбирали модель **BASE** (*Basically Available, Soft state, Eventual consistency*) — доступность и итоговую согласованность вместо строгих гарантий. Компромисс между согласованностью и доступностью при разделении сети описывает теорема CAP. Современные распределённые СУБД (Google Spanner, CockroachDB, YugabyteDB) предоставляют ACID-транзакции поверх [шардированных](https://llmdocs.ru/wiki/sharding.md) и [реплицированных](https://llmdocs.ru/wiki/replication.md) данных.

## См. также

- [Уровни изоляции транзакций](https://llmdocs.ru/wiki/isolation-levels.md)
- [MVCC](https://llmdocs.ru/wiki/mvcc.md)
- [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md)
- [Репликация баз данных](https://llmdocs.ru/wiki/replication.md)
- [NoSQL](https://llmdocs.ru/wiki/nosql.md)

## Источники

1. [T. Haerder, A. Reuter — Principles of Transaction-Oriented Database Recovery (ACM Computing Surveys, 1983)](https://dl.acm.org/doi/10.1145/289.291)
2. [PostgreSQL Documentation — Transactions (tutorial)](https://www.postgresql.org/docs/current/tutorial-transactions.html)
3. [PostgreSQL Documentation — Transaction Isolation](https://www.postgresql.org/docs/current/transaction-iso.html)
4. [PostgreSQL Documentation — Write-Ahead Logging](https://www.postgresql.org/docs/current/wal-intro.html)
5. [SQLite — Atomic Commit In SQLite](https://www.sqlite.org/atomiccommit.html)
6. [Jim Gray — The Transaction Concept: Virtues and Limitations (1981)](https://jimgray.azurewebsites.net/papers/thetransactionconcept.pdf)
