Ответ
Уровень изоляции Repeatable Read гарантирует, что в рамках одной транзакции повторные чтения одних и тех же строк вернут идентичные данные. Это предотвращает аномалию неповторяющегося чтения (non-repeatable read), когда другая транзакция изменяет или удаляет данные между двумя операциями SELECT внутри текущей транзакции.
Проблема (без Repeatable Read):
- Транзакция A читает строку, получая значение
balance = 100. - Транзакция B обновляет эту строку на
balance = 200и коммитит. - Транзакция A повторно читает ту же строку и видит
balance = 200. Это неожиданное изменение внутри транзакции.
Решение с Repeatable Read:
-- Устанавливаем уровень изоляции
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
-- Первое чтение. СУБД создает снимок данных или блокирует строки.
SELECT balance FROM accounts WHERE id = 1; -- Возвращает 100
-- Даже если другая транзакция сейчас попытается обновить эту строку,
-- она будет заблокирована (или изменения не будут видны) до конца нашей транзакции.
-- Второе чтение гарантированно вернет те же 100.
SELECT balance FROM accounts WHERE id = 1; -- Все еще 100
COMMIT;
Ключевые детали и отличия в реализациях:
- Защита: Предотвращает неповторяющееся чтение. В большинстве СУБД (например, PostgreSQL, MySQL с InnoDB) также предотвращает потерянное обновление (lost update).
- Не защищает от: Фантомного чтения (phantom read) — появления новых строк, удовлетворяющих условию запроса, из-за вставок другими транзакциями. Для защиты от фантомов нужен уровень
SERIALIZABLE. - Реализация: В PostgreSQL и Oracle используется механизм MVCC (Multi-Version Concurrency Control) с созданием снимков данных на начало транзакции. В SQL Server и MySQL (InnoDB с блокировками) данный уровень активно использует блокировки диапазонов и строк.