私は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文から)DBMSから返されます。
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;
上記のように、2番目の(重複した)select文は正しく動作します。どうして?