里使用Postgres 9.6,我遵循了https://stackoverflow.com/a/40325406/435563建议做一个INSERT
或SELECT
并返回得到的ID策略:INSERT或SELECT策略总是返回一行?
with ins as (
insert into prop (prop_type, norm, hash, symbols)
values (
$1, $2, $3, $4
) on conflict (hash) do
update set prop_type = 'jargon' where false
returning id)
select id from ins
union all
select id from prop where hash = $3
不过,有时这种没有返回。无论如何,我都会预料它会连续返回。我如何解决它以确保它始终返回一个ID?
注意,尽管没有返回一行,但行似乎在检查中存在。我相信这个问题可能与尝试通过两个会话同时添加相同的记录有关。
问题的表被定义为:
create table prop (
id serial primary key,
prop_type text not null references prop_type(name),
norm text not null,
hash text not null unique,
symbols jsonb
);
数据:
EDT DETAIL: parameters: $1 = 'jargon', $2 = 'j2', $3 = 'lXWkZSmoSE0mZ+n4xpWB', $4 = '[]'
如果我改变prop_type = 'jargon'
到prop_type = 'foo'
它的作品!即使给出where false
子句,如果表达式不会改变任何东西,看起来锁也不会被采用。这真的需要依赖于我猜测一个不会排在行内的值吗?还是有更好的方法来确保你获得锁定?
--- UPDATE ---
的总体情况是,应用程序尝试使用连接池(...自动提交)保存向无环图,并使用该查询来获取同时识别重复。 [事实证明,更聪明的是使用一个事务,只是序列化到一个连接。但是,当有争这里的行为是奇数]
外键约束似乎并没有影响到插入 - 如:
create table foo(i int unique, prop_id int references prop(id));
insert into foo values (1, 208);
insert into foo values (1, 208)
on conflict (i) do update set prop_id = 208 where false;
--> INSERT 0 0
insert into foo values (1, 208)
on conflict (i) do update set prop_id = -208 where false;
--> INSERT 0 0
注意一个与有效FK 208,其他无效-208。如果我使用完整模式将选择连接到其中任何一个上,那么在没有争用的情况下,它们都会按预期返回i = 1。
请发布的数据样本为好,如果我不是弄错它始终如果它返回一行,因此你甚至可以从XMIN告诉,XMAX已更新或插入 –
已添加数据。我想它与应用程序试图保存一个复杂的数据结构,其中该叶片出现两次,使用连接池相关。所以记录被添加到两个不同的连接中。 – shaunc
与您的更新我注意到哪里更新不会发生错误 - 与该答案将不同:) –