Read Committed¶
Read Committed — это уровень изоляции транзакций в системах управления базами данных (СУБД), при котором транзакция видит только те изменения данных, которые были зафиксированы (закоммичены) другими транзакциями. Данный уровень гарантирует, что чтение «грязных» данных (dirty read) невозможно, но допускает возникновение фантомных чтений (phantom read) и неповторяющегося чтения (non-repeatable read).
¶История и стандартизация
Концепция уровней изоляции транзакций была впервые формализована в 1992 году в стандарте ANSI/ISO SQL-92. В этом стандарте были определены четыре уровня изоляции: Read Uncommitted, Read Committed, Repeatable Read и Serializable. Read Committed был введён как компромиссный вариант, обеспечивающий более высокую степень согласованности данных, чем Read Uncommitted, но с меньшими накладными расходами, чем Repeatable Read.
Большинство современных реляционных СУБД, включая PostgreSQL, Oracle, Microsoft SQL Server и MySQL (с движком InnoDB), по умолчанию используют уровень изоляции Read Committed. Исключением является, например, СУБД IBM Db2, где по умолчанию применяется курсорная стабильность (Cursor Stability), которая функционально эквивалентна Read Committed.
¶Принцип работы
Основная гарантия уровня Read Committed заключается в том, что любое чтение данных в рамках транзакции возвращает только те строки, которые были зафиксированы на момент выполнения операции чтения. Это означает, что если транзакция A изменяет строку, но ещё не зафиксировала изменения, то транзакция B, выполняющаяся параллельно, не увидит эти изменения, пока транзакция A не выполнит COMMIT.
¶Механизмы реализации
Для обеспечения данного поведения СУБД используют различные механизмы:
- Блокировки чтения-записи (Read-Write Locks): В некоторых СУБД (например, в Microsoft SQL Server при использовании блокировок) транзакция, выполняющая запись, устанавливает исключительную блокировку (exclusive lock) на изменяемые строки. Транзакция, пытающаяся прочитать эти строки, вынуждена ждать снятия блокировки, то есть завершения пишущей транзакции (COMMIT или ROLLBACK). Этот подход может приводить к взаимным блокировкам (deadlocks) и снижению производительности при высокой конкуренции.
- Многоверсионность (Multiversion Concurrency Control, MVCC): Большинство современных СУБД (PostgreSQL, Oracle, MySQL/InnoDB) реализуют Read Committed через MVCC. В этом механизме каждая транзакция видит «снимок» данных на момент начала своего выполнения или на момент выполнения каждого отдельного запроса (в зависимости от реализации). При изменении данных создаётся новая версия строки, а старая остаётся доступной для чтения другими транзакциями. Таким образом, читающая транзакция не блокируется пишущей, и наоборот. В PostgreSQL, например, в режиме Read Committed каждый запрос в рамках транзакции видит снимок данных, зафиксированных на момент начала этого запроса.
¶Аномалии, допускаемые уровнем Read Committed
Несмотря на защиту от «грязного» чтения, уровень Read Committed не предотвращает две другие аномалии параллельного доступа:
¶Неповторяющееся чтение (Non-repeatable Read)
Эта аномалия возникает, когда в рамках одной транзакции один и тот же запрос на чтение данных возвращает разные результаты. Это происходит из-за того, что между двумя чтениями другая транзакция фиксирует изменения (обновление или удаление) тех же строк.
Пример:
- Транзакция A выполняет запрос:
SELECT balance FROM accounts WHERE id = 1;— возвращает 1000. - Транзакция B выполняет:
UPDATE accounts SET balance = 500 WHERE id = 1; COMMIT; - Транзакция A снова выполняет тот же запрос:
SELECT balance FROM accounts WHERE id = 1;— возвращает 500.
Таким образом, в рамках одной транзакции A значение баланса изменилось, что может привести к логическим ошибкам в приложении.
¶Фантомное чтение (Phantom Read)
Фантомное чтение — это частный случай неповторяющегося чтения, при котором между двумя выполнениями одного и того же запроса с условием (например, WHERE amount > 100) другая транзакция вставляет новые строки, удовлетворяющие этому условию. В результате второй запрос возвращает «фантомные» строки, которых не было при первом выполнении.
Пример:
- Транзакция A выполняет запрос:
SELECT * FROM orders WHERE amount > 100;— возвращает 2 строки. - Транзакция B выполняет:
INSERT INTO orders (amount) VALUES (200); COMMIT; - Транзакция A снова выполняет тот же запрос:
SELECT * FROM orders WHERE amount > 100;— возвращает 3 строки.
¶Сравнение с другими уровнями изоляции
Уровень Read Committed занимает промежуточное положение по степени изоляции и производительности.
| Уровень изоляции | Грязное чтение | Неповторяющееся чтение | Фантомное чтение |
|---|---|---|---|
| Read Uncommitted | Допускается | Допускается | Допускается |
| Read Committed | Исключено | Допускается | Допускается |
| Repeatable Read | Исключено | Исключено | Допускается (в стандарте SQL) |
| Serializable | Исключено | Исключено | Исключено |
- Read Uncommitted: Позволяет читать незафиксированные изменения, что может приводить к «грязному» чтению. Используется редко, в основном для задач, где точность данных не критична.
- Repeatable Read: Гарантирует, что в рамках одной транзакции повторные чтения одних и тех же строк дадут одинаковый результат. Однако в стандарте SQL допускает фантомное чтение. В некоторых СУБД (например, в PostgreSQL) этот уровень дополнительно защищает и от фантомов.
- Serializable: Самый строгий уровень, при котором транзакции выполняются так, как если бы они шли последовательно, одна за другой. Полностью исключает все аномалии, но требует наибольших накладных расходов и может приводить к частым ошибкам сериализации.
¶Применение
Уровень Read Committed является наиболее распространённым выбором для веб-приложений, интернет-магазинов, систем управления контентом (CMS) и других OLTP-систем (Online Transaction Processing), где требуется высокая производительность при большом количестве параллельных запросов. Он обеспечивает достаточный уровень согласованности для большинства бизнес-сценариев, не вводя излишних блокировок, характерных для более высоких уровней изоляции.
Однако для финансовых транзакций, где критична повторяемость чтения (например, расчёт баланса, формирование отчётов), может потребоваться использование Repeatable Read или Serializable.
¶Критика и ограничения
Основным недостатком Read Committed является возможность неповторяющегося чтения, что может приводить к так называемым «состояниям гонки» (race conditions) в приложениях. Например, при чтении текущего баланса и последующем списании средств, между этими двумя операциями другая транзакция может изменить баланс, что приведёт к некорректному итоговому значению. Для решения этой проблемы разработчики часто используют явные блокировки (например, SELECT ... FOR UPDATE), которые переводят чтение в режим монопольного доступа, фактически эмулируя поведение более высокого уровня изоляции.
Также в некоторых реализациях MVCC (например, в Oracle) уровень Read Committed может приводить к ошибке «snapshot too old», если версии строк, необходимые для чтения, были удалены сборщиком мусора до завершения транзакции.
¶Источники
- ISO/IEC 9075:1992, Information technology — Database languages — SQL.
- Berenson, H., Bernstein, P., Gray, J., Melton, J., O'Neil, E., & O'Neil, P. (1995). A critique of ANSI SQL isolation levels. ACM SIGMOD Record, 24(2), 1-10.
- Документация PostgreSQL: «Уровни изоляции транзакций».
- Документация MySQL: «InnoDB Transaction Isolation Levels».
- Документация Microsoft SQL Server: «Уровни изоляции (ядро СУБД)».
- Документация Oracle Database: «Data Concurrency and Consistency».
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


