在PG(nodejs)中尝试以下UPSERT:
WITH upsert_result AS(
INSERT INTO table1 (col1, col2)
VALUES($1,$2)
ON CONFLICT DO NOTHING
RETURNING *
)
SELECT * FROM upsert_result
UNION
SELECT * FROM table1 WHERE col1=$1
为什么我有时会得到空结果?
我的理解是,这里的UNION
应该通过获取冲突行来防止这种情况。
以下是表定义:
CREATE EXTENSION IF NOT EXISTS "ltree";
CREATE TABLE IF NOT EXISTS table1(
col1 TEXT NOT NULL UNIQUE REFERENCES table2 (col1) ON DELETE CASCADE,
col2 ltree NOT NULL
);
CREATE INDEX IF NOT EXISTS tree_col2_idx ON table1 USING gist (col2);
我期望查询返回新插入的行(如果具有相同col1
的行不存在)或现有行(如果具有相同col1
的行已经存在)。实际上,这是大多数情况下发生的事情,但在一些罕见的情况下,我从上面的插入中得到一个空结果。
1条答案
按热度按时间kgsdhlau1#
存在隐藏的争用条件。
冲突检查包括(必须包括!)来自(尚未)提交的并发事务处理的行。如果一个并发事务处理写入了您的事务处理现在试图UPSERT的行,则您的事务处理必须等待另一个并发事务处理完成。
如果另一个事务正常结束,
INSERT
将检测到冲突和DO NOTHING
,因此也不会返回该行。SELECT
看到的是与查询开始时相同的快照,也无法返回尚未看到的行。在此阅读详细的评估,尤其是“并发问题1”一章:
......以及如何克服它。
旁注:
UNION ALL
,不是UNION
,但这也在链接答案中。