Я столкнулся с проблемами состояния транзакций в PostgreSQL (возможно, не только psql). Я пытаюсь добиться такой простой задачи с использованием нескольких потоков:SELECT FOR UPDATE ошибочный результат
BEGIN;
SELECT * FROM t WHERE id = 1;
DELETE FROM t WHERE id = 1;
INSERT INTO t (id, value) VALUES (1, 'thread X'); -- X = 1,2,3,..
SELECT 1 FROM pg_sleep(10); -- only for race condition simulation
COMMIT;
Однако потоки сталкивающихся внутри этих операций, так что несколько вставок, выполненных (ключевой ошибкой первичного соударения). Таким образом, я пытался использовать SELECT FOR UPDATE заявление:
BEGIN;
SELECT * FROM t WHERE id = 1 FOR UPDATE;
DELETE FROM t WHERE id = 1;
INSERT INTO t (id, value) VALUES (1, 'thread X'); -- X = 1,2,3,..
SELECT 1 FROM pg_sleep(10); -- only for race condition simulation
COMMIT;
Сделки правильно блокированием FOR UPDATE заявление ждет других потоков фиксации.
Однако после того, как «семафор вверх» (проснувшись на это заявление после того, как другой поток транзакции совершил) пустой результирующий набор возвращается из СУБД, хотя данные правильно доступны в таблице (от INSERT заявления от более быстрого потока):
BEGIN;
SELECT * FROM t WHERE id = 1 FOR UPDATE; -- blocking ... then return 0 records WRONG
SELECT * FROM t WHERE id = 1 FOR UPDATE; -- second try ... returns 1 record CORRECT
DELETE FROM t WHERE id = 1;
INSERT INTO t (id, value) VALUES (1, 'thread X'); -- X = 1,2,3,..
SELECT 1 FROM pg_sleep(10); -- only for race condition simulation
COMMIT;
Как видно выше, второй (дублированный) оператор выбора ведет себя правильно. Зачем?