Postgres: SELECT FOR UPDATE не видит новые строки после снятия блокировки - PullRequest
0 голосов
/ 08 февраля 2019

Попытка поддержки БД PostgreSQL в моем приложении обнаружила это странное поведение.

Подготовка:

CREATE TABLE test(id INTEGER, flag BOOLEAN);
INSERT INTO test(id, flag) VALUES (1, true);

Предположим две одновременные транзакции ( Autocommit =false, READ_COMMITTED ) TX1 и TX2 :

TX1:

UPDATE test SET flag = FALSE WHERE id = 1;
INSERT INTO test(id, flag) VALUES (2, TRUE);
-- (wait, no COMMIT yet)

TX2:

SELECT id FROM test WHERE flag=true FOR UPDATE;
-- waits for TX1 to release lock

Теперь, если я COMMIT в TX1 , SELECT в TX2 возвращает пустой курсор.

Это странномне, потому что тот же эксперимент в Oracle и MariaDB приводит к выбору вновь созданной строки (id = 2).

Я не смог найти ничего об этом поведении в документации PG.Я что-то пропустил?Есть ли способ заставить сервер PG «обновить» видимость оператора после получения блокировки?

PS: PostgreSQL версии 11.1

1 Ответ

0 голосов
/ 15 февраля 2019

TX2 сканирует таблицу и пытается заблокировать результаты.

Сканирование видит моментальный снимок базы данных с начала запроса, поэтому не может видеть вставленные строки(или получил право каким-либо иным способом) путем одновременных изменений, которые начались после того снимка.

Именно поэтому вы не можете видеть строку с id 2.

Для id 1, это также верно, поэтому сканирование находит эту строку.Но запрос должен ждать, пока не будет снята блокировка.Когда это, наконец, происходит, он выбирает последнюю зафиксированную версию строки и снова выполняет проверку, так что строка также исключается.

Эта повторная проверка «EvalPlanQual» (для использования жаргона PostgreSQL) выполняется только для строккоторые были найдены во время сканирования, но были заблокированы.Вторая строка даже не найдена во время сканирования, поэтому там такой обработки не происходит.

Это немного странно, допустим.Но это не ошибка, это просто способ PostgreSQL.

Если вы хотите избежать таких аномалий, используйте уровень изоляции REPEATABLE READ.Тогда вы получите ошибку сериализации в таком случае и сможете повторить транзакцию, избегая подобных несоответствий.

...