Ответ
REPEATABLE_READ — это уровень изоляции транзакций, который гарантирует, что если транзакция повторно читает одни и те же данные, она получит идентичный результат. Он предотвращает Dirty Reads и Non-repeatable Reads, но может допускать Phantom Reads.
Характеристики и проблемы:
- Предотвращает:
- Dirty Read.
- Non-repeatable Read.
- Допускает:
- Phantom Read: Транзакция может увидеть новые строки, добавленные другими зафиксированными транзакциями после ее начала.
Как это работает: Транзакция "видит" снимок данных (snapshot) на момент своего первого оператора чтения. Все последующие чтения в рамках этой транзакции будут возвращать данные из этого снимка, даже если другие транзакции уже изменили и зафиксировали исходные данные.
Практический пример:
-- Транзакция 1 (уровень REPEATABLE_READ)
BEGIN TRANSACTION;
SELECT COUNT(*) FROM users WHERE active = true; -- Возвращает 5
-- Транзакция 2
BEGIN TRANSACTION;
INSERT INTO users (name, active) VALUES ('NewUser', true);
COMMIT;
-- Транзакция 1 (продолжение)
SELECT COUNT(*) FROM users WHERE active = true; -- Все еще возвращает 5 (Phantom Read предотвращен в некоторых СУБД)
UPDATE users SET active = false WHERE active = true; -- Может заблокировать больше строк, чем ожидалось
COMMIT;
Важно: В MySQL (с движком InnoDB) и некоторых других СУБД реализация REPEATABLE_READ с использованием механизма snapshot также предотвращает Phantom Reads за счет использования next-key locks. В PostgreSQL и Oracle этот уровень эквивалентен SERIALIZABLE в смысле snapshot изоляции.