假设我们有一个表格,用于描述用户的一篮子水果的内容。这基本上只是用户的映射 - >水果清单。
我们定期查询远程数据源并获取特定用户的新列表。然后,我们尝试用一组新行完全替换所有用户的当前行。例如:
在:
user fruit freshness
-------------------------------
...
47 'apple' 0.1
47 'pear' 9.5
47 'pear' 2.8
...
后:
user fruit freshness
-------------------------------
...
47 'apple' 93.9034
47 'banana' 0
...
给定一组新的行,有没有办法在postgres中进行 atomic 的替换?
以下不起作用:
BEGIN
DELETE FROM basket WHERE user=47
INSERT INTO basket ...
COMMIT
如果我们同时进行多个交易,postgres会很乐意订购这样的命令(没有锁定问题):
BEGIN
BEGIN
DELETE
DELETE
INSERT
INSERT <---- data inserted twice here
COMMIT
COMMIT
这将导致行数的两倍。
许多类似问题的答案声称第一个DELETE将锁定有问题的行,第二个事务必须等待,但这不是真的(无论出于何种原因)。这两笔交易都很高兴地在这里互相踩踏。
备注:
user
- >的地图fruit[]
。我可以把它全部放在一个jsonb列中,但是我不能在行上运行连接。加入很好:(答案 0 :(得分:1)
您可以锁定要修改的user_id
。如果您有users
表,则选择相应的行进行更新:
BEGIN;
SELECT user_id FROM users WHERE user_id = 47 FOR UPDATE;
DELETE FROM basket WHERE user_id = 47;
INSERT INTO basket ...
COMMIT;
或者,您可以使用咨询锁,例如:
BEGIN;
SELECT pg_advisory_lock('basket'::regclass::int, 47);
DELETE FROM basket WHERE user_id = 47;
INSERT INTO basket ...
SELECT pg_advisory_unlock('basket'::regclass::int, 47);
COMMIT;
中的明确锁定