【发布时间】:2016-11-01 14:39:09
【问题描述】:
我遇到了 PostgreSQL(可能不仅仅是 psql)事务竞争条件问题。我正在尝试使用多个线程来完成这样一个简单的任务:
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;
如上所示,第二个(重复的)select 语句表现正确。为什么?
【问题讨论】:
标签: sql multithreading postgresql transactions isolation-level