Ответ
Уровень изоляции READ COMMITTED (чтение зафиксированных данных) является уровнем по умолчанию во многих СУБД (например, PostgreSQL). Он предотвращает «грязное чтение» (Dirty Read), но допускает следующие аномалии:
1. Неповторяющееся чтение (Non-repeatable Read) Одна и та же строка, прочитанная дважды в рамках одной транзакции, может иметь разные значения, потому что другая, параллельная транзакция изменила и зафиксировала эту строку между двумя чтениями.
2. Фантомное чтение (Phantom Read) Набор строк, полученный в результате двух одинаковых запросов в одной транзакции, может различаться из-за того, что другая транзакция добавила или удалила строки, удовлетворяющие условию запроса.
Практический пример в PostgreSQL:
-- Сессия 1 (Транзакция A)
BEGIN; -- Уровень изоляции READ COMMITTED
SELECT balance FROM accounts WHERE user_id = 1; -- Чтение 1: допустим, 100
-- Сессия 2 (Транзакция B) выполняет и коммитит:
BEGIN;
UPDATE accounts SET balance = 50 WHERE user_id = 1;
COMMIT;
-- Сессия 1 снова читает ту же строку:
SELECT balance FROM accounts WHERE user_id = 1; -- Чтение 2: теперь 50 (Non-repeatable Read)
COMMIT;
Как с этим бороться?
Для предотвращения этих аномалий нужно использовать более строгий уровень изоляции — REPEATABLE READ или SERIALIZABLE. В REPEATABLE READ СУБД (как PostgreSQL) использует снимки данных (snapshot), чтобы гарантировать, что транзакция видит данные в одном и том же состоянии на протяжении всей своей работы.