Медиаблог /

Что такое транзакция в базе данных: ACID, команды и уровни изоляции

27 августа 2026

Что такое транзакция в базе данных: ACID, команды и уровни изоляции

Транзакция в базе данных — набор SQL-операций, которые выполняются как единое целое по принципу «всё или ничего»: либо все изменения фиксируются командой COMMIT, либо полностью отменяются через ROLLBACK. Надёжность транзакций определяется четырьмя гарантиями — моделью ACID.

Разработчик за компьютером пишет транзакции в базе данных

В статье разберём, что такое транзакция в СУБД, как работают команды BEGIN, COMMIT, ROLLBACK и SAVEPOINT, какие уровни изоляции защищают данные при параллельном доступе и как всё это реализовано в PostgreSQL.

image

Учитесь бесплатно за счёт государства

Экономия до 100 000 ₽ на любой программе

Выбрать курс

Что такое транзакция в базе данных

Транзакция в базе данных — логически завершённая единица работы, которая переводит БД из одного согласованного состояния в другое. SQL-транзакция объединяет одну или несколько DML-операций (INSERT, UPDATE, DELETE) и гарантирует два исхода: COMMIT — все изменения зафиксированы в БД, или ROLLBACK — все изменения отменены, БД возвращается в исходное состояние.

СУБД считает набор операций неделимым. Если в процессе выполнения происходит сбой или нарушение ограничения целостности, система автоматически откатывает всё, что было сделано в рамках этой транзакции.

Принцип «всё или ничего» и пример банковского перевода

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

BEGIN;

UPDATE accounts SET balance = balance — 5000 WHERE id = 1;

UPDATE accounts SET balance = balance + 5000 WHERE id = 2;

COMMIT;

Без транзакции в БД опасность очевидна: если первый UPDATE выполнен, а второй завершился ошибкой — деньги спишутся, но не зачислятся. Транзакция исключает такой исход: при ошибке СУБД автоматически откатит первое изменение через ROLLBACK.

Атомарность транзакции означает, что в базе не остаётся «полувыполненных» операций — либо оба UPDATE применились, либо ни один.

Зачем нужны транзакции: задачи и области применения

Транзакция в БД решает три задачи:

  • защищает от частичного применения изменений при ошибке или сбое приложения;
  • гарантирует сохранность данных при отказе сервера — незафиксированные изменения автоматически отменяются;
  • обеспечивает согласованность при параллельном доступе нескольких пользователей к одним данным.

Целостность данных через транзакции критична в банкинге и финансовых платформах, интернет-магазинах (списание товара + создание заказа), ERP-системах и складском учёте. Простыми словами: транзакция в БД — это страховка от неполных изменений в любой многошаговой операции.

Свойства ACID — основа надёжных транзакций

Четыре свойства ACID обеспечивают надёжность транзакций в базе данных

ACID определяет четыре стандартных свойства транзакций в базе данных, которые СУБД должна гарантировать:

  • Atomicity (атомарность) — всё или ничего;
  • Consistency (согласованность) — БД переходит между валидными состояниями;
  • Isolation (изолированность) — транзакции не мешают друг другу;
  • Durability (долговечность) — зафиксированные данные сохраняются при сбое.

ACID реализуется через механизмы СУБД: блокировки, многоверсионный доступ к данным и журнал транзакций.

Атомарность и Согласованность

Атомарность гарантирует: если хотя бы одна операция транзакции завершилась с ошибкой, все предыдущие изменения откатываются через ROLLBACK. Пример нарушения без транзакции: UPDATE на списание выполнен, но UPDATE на зачисление упал с ошибкой внешнего ключа — баланс уменьшился, но деньги не поступили. Транзакция исключает этот сценарий.

Согласованность означает, что транзакция переводит базу из одного валидного состояния в другое. Валидность проверяется через ограничения целостности: внешние ключи (FOREIGN KEY), условия (CHECK), уникальность (UNIQUE). Если ограничение нарушено — ACID-транзакция откатится, не допустив некорректного состояния БД.

Изолированность и Долговечность

Изолированность означает, что параллельные транзакции не влияют на результаты друг друга. Степень изолированности задаётся уровнями изоляции — от минимальной (Read Uncommitted) до максимальной (Serializable). Именно изолированность управляется через уровни изоляции транзакций, которые разбираются в отдельном разделе.

Долговечность гарантирует: после успешного COMMIT изменения сохраняются в БД даже при отказе питания или краше сервера. Долговечность обеспечивается журналом транзакций — специальным файлом, куда СУБД записывает все DML-операции до подтверждения. При восстановлении система дочитывает журнал и воспроизводит незавершённые фиксации.

Команды управления транзакциями в SQL

SQL-команды транзакций в редакторе кода на экране ноутбука

Три базовые команды управляют жизненным циклом транзакции в базе данных:

  • BEGIN — запускает транзакцию; все последующие DML-операции входят в её состав;
  • COMMIT — фиксирует все изменения транзакции в БД окончательно;
  • ROLLBACK — отменяет все незафиксированные изменения с момента BEGIN.

BEGIN и COMMIT: запуск и фиксация транзакции

BEGIN инициирует явную транзакцию. Всё, что выполняется после BEGIN до COMMIT или ROLLBACK, является частью этой транзакции.

BEGIN;

UPDATE cars SET max_speed = 240 WHERE id = 1;

— Внутри транзакции изменение видно текущему сеансу:

SELECT max_speed FROM cars WHERE id = 1; — вернёт 240

COMMIT;

— После COMMIT данные зафиксированы для всех сеансов:

SELECT max_speed FROM cars WHERE id = 1; — вернёт 240

COMMIT фиксирует изменения постоянно. После COMMIT отменить их командой ROLLBACK уже невозможно — данные записаны в БД и видны всем пользователям.

ROLLBACK: полная отмена незафиксированных изменений

ROLLBACK отменяет все операции транзакции с начала BEGIN, возвращая базу в исходное состояние. Выполняется как вручную, так и автоматически при ошибке внутри транзакции.

BEGIN;

UPDATE cars SET max_speed = 300 WHERE id = 1;

ROLLBACK;

— Изменение полностью отменено:

SELECT max_speed FROM cars WHERE id = 1; — вернёт исходное значение

Откат изменений через ROLLBACK полный: ни одно из DML-изменений транзакции не попадает в БД. Без BEGIN вернуть UPDATE невозможно — без явной транзакции запрос уже зафиксирован автоматически.

SAVEPOINT и ROLLBACK TO: частичный откат внутри транзакции

SAVEPOINT создаёт именованную точку внутри транзакции. ROLLBACK TO откатывает только изменения после этой точки, сохраняя все предыдущие операции. Вся транзакция при этом продолжает выполняться.

BEGIN;

UPDATE orders SET status = ‘processing’ WHERE id = 100;

SAVEPOINT after_status;

UPDATE inventory SET stock = stock — 1 WHERE product_id = 5;

— Что-то пошло не так — откатываем только складскую операцию:

ROLLBACK TO after_status;

— Статус заказа сохранён, изменение склада отменено:

COMMIT;

После ROLLBACK TO after_status обновление склада отменяется, но статус заказа остаётся processing. COMMIT фиксирует только изменение статуса. Точки сохранения поддерживают PostgreSQL, Oracle и MySQL. SAVEPOINT позволяет реализовать частичный откат транзакции — без отмены всей транзакции целиком.

Типы транзакций в SQL

Схема классификации типов транзакций в реляционных базах данных

В SQL различают четыре типа транзакций:

Тип
Управление
Применение
Явная Начинается с BEGIN, завершается COMMIT / ROLLBACK вручную Многошаговые операции с полным контролем
Неявная Запускается автоматически при DML; требует явного COMMIT / ROLLBACK SQL Server при IMPLICIT_TRANSACTIONS=ON
Вложенная BEGIN внутри BEGIN; реально контролируется только внешней транзакцией Процедуры и вызовы подмодулей
Автономная Независима от вызывающей транзакции Логирование ошибок, аудит

Отдельно стоит режим автофиксации (autocommit): каждый одиночный SQL-запрос автоматически оборачивается в транзакцию с немедленным COMMIT. Именно поэтому UPDATE без BEGIN нельзя откатить — он уже зафиксирован до того, как вы успели вызвать ROLLBACK.

Явные транзакции и режим autocommit

Явная транзакция — самый распространённый тип: разработчик пишет BEGIN + COMMIT/ROLLBACK вручную и получает полный контроль над многошаговыми операциями.

В PostgreSQL по умолчанию включён режим автофиксации: каждый запрос вне явной транзакции сразу фиксируется. Это причина, почему одиночный UPDATE без BEGIN нельзя откатить — СУБД уже выполнила COMMIT автоматически. BEGIN отключает autocommit до завершения текущей транзакции.

Неявная транзакция используется в SQL Server при включённом параметре IMPLICIT_TRANSACTIONS=ON: DML-запрос запускает транзакцию автоматически, но завершение требует явного COMMIT или ROLLBACK от разработчика.

Вложенные и автономные транзакции

Вложенная транзакция в SQL возникает, когда BEGIN выполняется внутри уже открытой транзакции. Внутренний COMMIT не фиксирует данные немедленно — изменения сохраняются только при завершении внешней транзакции. Если внешняя откатывается, откатываются и все вложенные изменения: только внешняя транзакция реально управляет исходом.

Автономная транзакция полностью независима от вызывающей. COMMIT или ROLLBACK внутри автономной транзакции не влияет на исход родительской — и наоборот. Применяется для записи событий в журнал аудита или логирования ошибок: запись сохраняется, даже если основная транзакция откатилась.

Феномены параллельного выполнения транзакций

Серверный шкаф в дата-центре обрабатывает параллельные транзакции

При параллельном доступе нескольких транзакций к одним данным возникают аномалии данных. Их пять, и каждый феномен конкурентного доступа возникает при недостаточной изоляции транзакций.

Феномены по возрастанию серьёзности:

  1. потерянное обновление;
  2. грязное чтение;
  3. неповторяющееся чтение;
  4. фантомное чтение;
  5. аномалия сериализации.

Потерянное обновление и грязное чтение

Потерянное обновление (lost update): транзакция Б перезаписывает изменения, которые внесла транзакция А, не зная об этих изменениях. Результат — обновление А «потеряно». Предотвращается блокировкой строки на запись начиная с уровня Read Committed.

Грязное чтение (dirty read): транзакция читает незафиксированные изменения другой транзакции. Если та откатывается — читающая транзакция использовала данные, которых в БД никогда не существовало. Грязное чтение предотвращается уровнем Read Committed. В PostgreSQL оно технически невозможно даже на уровне Read Uncommitted — механизм многоверсионного доступа (MVCC) исключает чтение незафиксированных данных.

Неповторяющееся и фантомное чтение

Неповторяющееся чтение: транзакция дважды читает одну и ту же строку и получает разные значения, потому что другая транзакция успела изменить или удалить эту строку между двумя SELECT. Предотвращается уровнем Repeatable Read.

Фантомное чтение (phantom read): транзакция дважды выполняет одинаковый запрос с условием, но во второй раз получает дополнительные строки — их добавила другая транзакция. Ключевое отличие от неповторяющегося чтения: меняется не значение строки, а их количество. По стандарту SQL фантомное чтение предотвращается уровнем Serializable. В PostgreSQL уровень Repeatable Read также защищает от фантомного чтения — это расширение стандарта.

Аномалия сериализации

Аномалия сериализации (serialization anomaly) возникает, когда результат параллельного выполнения транзакций не совпадает ни с одним вариантом их последовательного выполнения.

Пример: транзакция Т1 меняет запись Toyota → BMW, транзакция Т2 одновременно меняет BMW → Toyota. При любой последовательности (Т1 затем Т2 или Т2 затем Т1) итоговое значение будет Toyota. Но при параллельном выполнении обе видят исходные данные и обе применяют изменения — итог невозможен ни при каком последовательном запуске.

Аномалия сериализации предотвращается только уровнем Serializable.

Уровни изоляции транзакций

Уровень изоляции транзакции определяет допустимые феномены параллельного доступа. Чем выше уровень — тем строже изоляция и тем ниже производительность при высокой конкурентности.

Установка уровня изоляции в PostgreSQL:

BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;

Матрица феноменов и уровней изоляции транзакций в СУБД:

Уровень изоляции
Потерянное обновление
Грязное чтение
Неповт. чтение
Фантомное чтение
Аном. сериализации
Read Uncommitted ✓*
Read Committed
Repeatable Read ✓**
Serializable
Snapshot (MVCC) ✗***

Хотите сменить профессию или повысить квалификацию?

Федеральный проект «Активные меры содействия занятости» даёт возможность пройти обучение бесплатно за счёт государства

  • Программы от ведущих вузов России — от 2 месяцев
  • Удостоверение или диплом установленного образца
  • Центр карьеры: 7 500+ вакансий, помощь с трудоустройством
Оставить заявку
image

✓ — феномен возможен; ✗ — предотвращён. * В PostgreSQL Read Uncommitted = Read Committed: MVCC исключает грязное чтение. ** В PostgreSQL Repeatable Read также предотвращает фантомное чтение. *** Snapshot предотвращает фантомное чтение, но не аномалию сериализации без SSI.

Уровни изоляции транзакций в базе данных: шкала строгости и производительности

Read Uncommitted и Read Committed

Read Uncommitted — самый слабый уровень. По стандарту SQL допускает грязное чтение. В PostgreSQL этот уровень технически работает как Read Committed: многоверсионная модель параллельного доступа (MVCC) делает грязное чтение физически невозможным — читатель всегда получает снимок зафиксированных данных.

Read Committed — уровень изоляции по умолчанию в PostgreSQL и SQL Server. При каждом SELECT создаётся новый снимок зафиксированных данных. Транзакция не видит незафиксированных изменений, но при повторном чтении той же строки может получить другой результат — если другая транзакция успела выполнить COMMIT между двумя запросами.

Repeatable Read

На уровне Repeatable Read снимок базы данных создаётся один раз — при первом запросе после BEGIN — и транзакция работает с ним до завершения. Повторное чтение той же строки всегда вернёт одинаковый результат.

В PostgreSQL этот уровень дополнительно предотвращает фантомное чтение — поведение, которого стандарт SQL не требует. При конкурентном обновлении одной строки двумя транзакциями PostgreSQL вернёт ошибку:

ERROR: could not serialize access due to concurrent update

В этом случае транзакцию необходимо повторить.

Serializable и Snapshot (MVCC)

Serializable — максимальный уровень изоляции транзакций. Снимок создаётся сразу после BEGIN, и СУБД гарантирует: результат параллельного выполнения идентичен какому-либо последовательному. При конфликтах возникает ошибка сериализации, и транзакцию нужно повторить. Serializable предотвращает все пять феноменов, но снижает производительность при высокой нагрузке.

Snapshot через механизм многоверсионного доступа (MVCC) даёт каждой транзакции собственный снимок данных на момент начала. Ключевое преимущество: читатели не блокируют писателей, и наоборот. PostgreSQL использует MVCC для реализации всех уровней изоляции — именно это объясняет его поведение на уровне Read Uncommitted.

Транзакции в PostgreSQL: практические примеры

MVCC в базе данных: параллельные транзакции читают собственные снимки данных

PostgreSQL полностью поддерживает ACID, а параллельность реализует через механизм многоверсионного доступа (MVCC). Для практической работы с транзакциями в PostgreSQL используется инструмент psql — интерактивная командная строка:

sudo -u postgres psql postgres

Далее — два практических примера управления транзакциями в PostgreSQL.

Базовые операции BEGIN, COMMIT и ROLLBACK

Создадим тестовую таблицу и проверим полный цикл транзакции:

— Создаём тестовую таблицу

CREATE TABLE cars (id SERIAL PRIMARY KEY, model VARCHAR(50), max_speed INT);

INSERT INTO cars (model, max_speed) VALUES (‘Toyota’, 180);

— Пример с ROLLBACK:

BEGIN;

UPDATE cars SET max_speed = 250 WHERE id = 1;

— Внутри транзакции текущий сеанс видит незафиксированное изменение:

SELECT max_speed FROM cars WHERE id = 1; — 250

ROLLBACK;

— После ROLLBACK данные не изменились:

SELECT max_speed FROM cars WHERE id = 1; — 180

— Пример с COMMIT:

BEGIN;

UPDATE cars SET max_speed = 220 WHERE id = 1;

COMMIT;

— После COMMIT изменение зафиксировано для всех сеансов:

SELECT max_speed FROM cars WHERE id = 1; — 220

Ключевой момент: внутри транзакции PostgreSQL показывает собственные незафиксированные изменения текущему сеансу. Другие сеансы на уровне Read Committed увидят значение 180 до тех пор, пока не будет выполнен COMMIT.

Пример с SAVEPOINT в PostgreSQL

Пример транзакции в БД с частичным откатом — обновление заказа и склада:

BEGIN;

— Шаг 1: обновляем статус заказа

UPDATE orders SET status = ‘processing’ WHERE id = 100;

— Создаём точку сохранения после успешного шага

SAVEPOINT after_status;

— Шаг 2: списываем товар со склада

UPDATE inventory SET stock = stock — 1 WHERE product_id = 5;

— Что-то пошло не так — откатываем только шаг 2:

ROLLBACK TO after_status;

— Шаг 1 (статус заказа) сохранён, шаг 2 (склад) отменён:

COMMIT;

После ROLLBACK TO after_status обновление склада отменяется, но статус заказа остаётся processing. COMMIT фиксирует только изменение статуса. Частичный откат транзакции через SAVEPOINT в PostgreSQL позволяет не терять уже выполненную работу при ошибке в одном из шагов.

Ошибки транзакций и их обработка

Механизм блокировок в базе данных защищает данные при параллельном доступе

При параллельной работе с базой данных транзакции сталкиваются с тремя типовыми проблемами: взаимная блокировка (deadlock), переполнение журнала транзакций и ошибка сериализации. Каждая требует отдельной стратегии обработки.

Взаимная блокировка (Deadlock): причины и предотвращение

Взаимная блокировка в базе данных — ситуация, когда две транзакции взаимно ждут ресурсов, заблокированных друг другом, и ни одна не может продолжить выполнение.

Шаг
Транзакция А
Транзакция Б
1 Блокирует строку 1 Блокирует строку 2
2 Ожидает строку 2 Ожидает строку 1
3 ← взаимная блокировка → ← взаимная блокировка →

СУБД обнаруживает дедлок через граф ожидания: если граф содержит цикл, система выбирает транзакцию-«жертву» и откатывает её. Приложение должно перехватывать эту ошибку и повторять транзакцию.

Три правила профилактики взаимных блокировок:

  • одинаковый порядок доступа — всегда обращайтесь к таблицам и строкам в одном порядке во всех транзакциях;
  • короткие транзакции — чем меньше время удержания блокировок, тем ниже вероятность конфликта;
  • минимальные блокировки — не удерживайте блокировки во время ожидания ввода пользователя или внешних запросов.

Граф ожидания дедлока: транзакция А и Б блокируют друг друга

Журнал транзакций: функции и переполнение

Журнал транзакций — файл, куда СУБД записывает все DML-операции до COMMIT или ROLLBACK. Он обеспечивает букву D в ACID: зафиксированные данные не теряются при сбое, а незафиксированные изменения можно откатить при любом исходе.

Три функции журнала транзакций:

  • запись всех изменений до подтверждения — основа устойчивости транзакции;
  • откат незафиксированных изменений при сбое или явном ROLLBACK;
  • восстановление данных после аварийного отключения сервера.

Переполнение журнала возникает при долгих транзакциях, отсутствии резервного копирования или нехватке места на диске. В SQL Server предусмотрены три режима работы журнала: SIMPLE (автоочистка после резервного копирования БД), FULL (полный контроль, обязателен регулярный backup журнала), BULK_LOGGED (компромисс для массовых операций).

Профилактика переполнения: регулярное резервное копирование журнала транзакций, короткие транзакции и мониторинг размера файла журнала.

Журнал транзакций базы данных — поток операций и мониторинг

Хотите освоить работу с базами данных и стать аналитиком данных? В рамках федерального проекта «Активные меры содействия занятости» доступно обучение по программе «Специалист по аналитике и базам данных в информационных системах» — с нуля, онлайн, без затрат. Смотрите каталог доступных программ.

Часто задаваемые вопросы

Что такое транзакция в базе данных простыми словами?

Транзакция — набор SQL-операций, которые СУБД выполняет как единое действие: либо все изменения применяются и фиксируются (COMMIT), либо ни одно не сохраняется (ROLLBACK). Классический пример — банковский перевод: списание с одного счёта и зачисление на другой должны произойти вместе или не произойти вовсе.

Что означает ACID в контексте баз данных?

ACID — четыре гарантии надёжных транзакций: Atomicity (атомарность — всё или ничего), Consistency (согласованность — БД переходит между валидными состояниями), Isolation (изолированность — транзакции не мешают друг другу), Durability (долговечность — зафиксированные данные сохраняются при сбое). Реализуются через механизмы СУБД: блокировки, MVCC, журнал транзакций.

В чём разница между COMMIT и ROLLBACK?

COMMIT окончательно сохраняет все изменения транзакции в базе данных. ROLLBACK отменяет все незафиксированные изменения с момента BEGIN, возвращая базу в исходное состояние. После COMMIT отменить изменения через ROLLBACK невозможно — данные уже зафиксированы.

Можно ли откатить только часть транзакции?

Да — через команду SAVEPOINT. Создайте точку сохранения внутри транзакции (SAVEPOINT name), а при необходимости выполните ROLLBACK TO name. Это отменит изменения только после точки, сохранив более ранние операции. Вся транзакция завершается обычным COMMIT. Полный пример с кодом — в разделе «Пример с SAVEPOINT в PostgreSQL».

Зачем нужен BEGIN, если можно писать SQL-запросы напрямую?

Без BEGIN каждый запрос выполняется в режиме автофиксации (autocommit) — автоматически оборачивается в отдельную транзакцию и немедленно фиксируется. Это значит: одиночный UPDATE без BEGIN нельзя откатить, он уже зафиксирован. BEGIN позволяет объединить несколько операций в одну транзакцию с явным контролем COMMIT и ROLLBACK.

Чем уровни изоляции отличаются друг от друга?

Каждый уровень определяет допустимые аномалии параллельного доступа. Read Committed (по умолчанию в PostgreSQL) предотвращает грязное чтение. Repeatable Read добавляет защиту от неповторяющегося чтения. Serializable устраняет все феномены, включая аномалию сериализации — самый строгий и медленный уровень. Матрица феноменов и уровней — в разделе «Уровни изоляции транзакций».

Как избежать взаимной блокировки (deadlock) в базе данных?

Три правила профилактики: первое — всегда обращайтесь к таблицам и строкам в одном порядке во всех транзакциях; второе — минимизируйте длительность транзакций, чем короче, тем меньше вероятность конфликта; третье — не удерживайте блокировки во время ожидания ввода пользователя или внешних запросов.

Почему в PostgreSQL Read Uncommitted работает как Read Committed?

PostgreSQL реализует многоверсионную модель параллельного доступа (MVCC), при которой читатели всегда видят снимок зафиксированных данных. Грязное чтение технически невозможно в этой архитектуре — читатель получает версию данных на момент запроса, не видя незафиксированных изменений других транзакций.

Чем вложенная транзакция отличается от автономной?

Вложенная транзакция (BEGIN внутри BEGIN) контролируется только внешней: внутренний COMMIT не фиксирует данные до завершения внешней, откат внешней отменяет и внутренние изменения. Автономная транзакция полностью независима — её COMMIT/ROLLBACK не зависит от исхода вызывающей. Применяется для аудита и логирования ошибок.

Когда стоит использовать уровень изоляции Serializable?

Serializable необходим, когда результат параллельного выполнения должен быть идентичен последовательному — финансовые операции, бухгалтерский учёт, системы инвентаризации. Из-за возможных ошибок сериализации и повторных попыток применяйте его только там, где строгая согласованность данных важнее производительности.

Подайте заявку —
забронируйте место в группе

45 000 мест на 2026 год. Бесплатное обучение по федеральному проекту «Активные меры содействия занятости»

  • Онлайн
  • От 2 месяцев
  • Бесплатно
  • Диплом
Учиться бесплатно
icon