在Postgres中使用乐观锁定和事务更新状态?

问题描述

假设我有两个这样的表:

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

处理伪代码:

  1. 修改检索到的asset_attributes
  2. 插入新的returning id记录update assets set current_assets_attributes_id = yyy where id = xxx
  3. commit
  4. 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。