Repeatable Read: согласованный снимок для нескольких запросов
Сравниваем Read Committed и Repeatable Read на отчёте, который выполняет несколько запросов.
- Начало транзакцииВыбираем уровень Repeatable Read
- Первое чтениеФиксируется снимок видимых данных
- Следующие чтенияИспользуют тот же снимок до конца транзакции
Отчёт сначала посчитал заказы, затем их общую сумму. Между запросами добавился ещё один заказ, и две цифры уже относятся к разным состояниям базы. В PostgreSQL 12 режим Repeatable Read позволяет читать один снимок на протяжении транзакции. Увидим разницу в двух соединениях и обсудим, когда такой снимок нужен.
Готовим данные
CREATE TABLE demo_report (id integer PRIMARY KEY, amount integer NOT NULL);
INSERT INTO demo_report VALUES (1, 100);
-- Соединение A
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT count(*), sum(amount) FROM demo_report;Первое обычное чтение закрепляет снимок для транзакции Repeatable Read. Теперь оставьте соединение A открытым и выполните добавление из второго соединения. Важно завершить его фиксацией: незавершённые изменения другого участника не позволяют показать нужное различие между уровнями изоляции.
-- Соединение B, режим autocommit
INSERT INTO demo_report VALUES (2, 200);
-- Снова соединение A
SELECT count(*), sum(amount) FROM demo_report;
COMMIT;
SELECT count(*), sum(amount) FROM demo_report;Что должно измениться
Внутри транзакции A ожидается прежняя пара: одна строка и сумма сто. После COMMIT новый запрос должен увидеть две строки и сумму триста. Для сравнения очистите тестовые данные до исходного состояния и повторите сценарий с Read Committed: там каждое новое выражение получает собственный снимок. Ожидаемые числа описывают контролируемую последовательность без посторонних записей.
Не держите снимок слишком долго
Не оставляйте отчётную транзакцию открытой на время разговора с пользователем или ожидания внешнего API. Длительный снимок удерживает старые версии строк и осложняет обслуживание активно меняющихся таблиц. Начинайте транзакцию непосредственно перед чтением и завершайте после получения необходимых данных. Если отчёт строится несколькими обработчиками, явно проверьте, используют ли они одно соединение и одну транзакцию. Само совпадение уровня изоляции не объединяет независимые снимки.
Одинаковый снимок ещё не защищает любое правило приложения. Два участника могут прочитать одно состояние, изменить разные строки и нарушить общее ограничение. Для таких случаев нужны блокировки либо Serializable с повтором всей транзакции при ошибке сериализации. У отчёта отдельно проверьте снимок, своевременное завершение и обработку отказа.
