问题描述
假设我有两个这样的表:
CREATE TABLE IF NOT EXISTS assets (
id uuid DEFAULT uuid_generate_v4() NOT NULL PRIMARY KEY,created timestamp DEFAULT Now() NOT NULL,customer uuid NOT NULL
);
CREATE TABLE IF NOT EXISTS asset_attributes (
id uuid DEFAULT uuid_generate_v4() NOT NULL PRIMARY KEY,asset uuid NOT NULL,attributes jsonb NOT NULL
);
我有assets
个客户所有; assets
的{{1}}可能会随时间变化。我需要能够引用旧版本的attributes
,而不是attributes
表中的UPDATE
列,而是在{{1 }}表。有时称为“非破坏性更新”。
assets
我可以使用INSERT
,总排序等来获取给定asset_attributes
的最新INSERT INTO asset_attributes
(
asset,attributes
)
VALUES
(
'92675e0c-7473-435f-b48e-8de1feb2164b','{ "foo": "bar" }'::jsonb
)
RETURNING id
值。
我的服务器的工作方式是为给定的asset_attributes
获取最新的asset
,对其进行一些处理,然后推送新的一行。
现在,问题在于,如果两个进程尝试同时执行此操作,那么在第二个进程完成之前可能会推入一个新值,因此它将在一个过时的值上工作。
我想发生的是对陈旧值的更新失败,以便该进程知道从最新值重新开始。
伪代码:
GROUP BY
我不确定为asset_attributes
编写sql的最佳方法是什么。
如何使用Postgres实现此目标?
我试图解决的问题:
asset
解决方法
通过在assets
表中添加assets
,我会用一块石头杀死两只鸟。
然后,我将select a.id,aa.attributes
from assets a
join asset_attributes aa
on aa.id = a.current_assets_attributes_id
where a.id = xxx
for update of assets;
行用作锁,如下所示:
attributes
处理伪代码:
- 修改检索到的
asset_attributes
- 插入新的
returning id
记录update assets set current_assets_attributes_id = yyy where id = xxx
-
commit
-
rollback
(或asset
),从而释放锁
其他尝试修改同一select. . . for update
的进程将在current_assets_attributes_id
上阻塞。
只要您使用assets
,这也可以在不将select. . . where id = xxx. . . for update of assets
添加到update
表的情况下进行,因为锁定并不关心您是否实际执行new Function()
并且将阻止任何其他进程锁定该行,直到拥有该锁的事务结束为止。
一种简单的方法是在INSERT的WHERE条件中包括最新条目的ID和最新条目的条件。 这可以在EXISTS()子句中完成,当且仅当ID仍是最新条目时,该子句的值为TRUE。
为使该方案起作用,必须在INSERT之后立即提交COMMIT。