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

Postgresql 在Postgres中使用乐观锁定和事务更新状态?,postgresql,transactions,Postgresql,Transactions,假设我有两张这样的桌子: 如果不存在资产,则创建表 id uuid默认uuid_生成_v4非空主键, 创建的时间戳默认值现在不为空, 客户uuid不为空 ; 如果不存在资产属性,则创建表 id uuid默认uuid_生成_v4非空主键, 创建的时间戳默认值现在不为空, 资产uuid不为空, 属性jsonb不为空 ; 我拥有客户拥有的资产;资产可以具有随时间变化的属性。我需要能够引用旧版本的属性,因此我不是更新资产表中的列,而是在资产属性表中插入新行。这有时称为非破坏性更新 插入到资产属性中 资产

假设我有两张这样的桌子:

如果不存在资产,则创建表 id uuid默认uuid_生成_v4非空主键, 创建的时间戳默认值现在不为空, 客户uuid不为空 ; 如果不存在资产属性,则创建表 id uuid默认uuid_生成_v4非空主键, 创建的时间戳默认值现在不为空, 资产uuid不为空, 属性jsonb不为空 ; 我拥有客户拥有的资产;资产可以具有随时间变化的属性。我需要能够引用旧版本的属性,因此我不是更新资产表中的列,而是在资产属性表中插入新行。这有时称为非破坏性更新

插入到资产属性中 资产 属性 价值观 ‘92675e0c-7473-435f-b48e-8de1feb2164b’, “{foo:bar}”:jsonb 返回id 我可以使用GROUP BY、total ordering等方法获取给定资产的最新资产属性值

我的服务器通过获取给定资产的最新资产属性,对其进行一些处理,然后推送新行来工作

现在的问题是,如果两个进程同时尝试这样做,那么在第二个进程完成之前可能会推送一个新值,因此它将处理一个过时的值

我希望发生的是,对过时值的更新失败,以便流程知道从最新值重新开始

伪代码:

流程属性资产id: 让latest_attributes=fetch_latest_attributesasset_id 让next\u attributes=do\u worklatest\u attributes let did_update_succeed=从上一个资产id、最新属性、下一个属性更新属性 如果没有,更新没有成功 然后 //从头开始再试一次 进程属性资产id 我不确定编写SQL for update_attributes_from_previous的最佳方法是什么

我怎样才能通过博士后实现这一目标

我的解决方案尝试:

插入到资产属性中资产,属性 选择 “92675e0c-7473-435f-b48e-8de1feb2164b”作为资产, “{foo:bar}”:jsonb作为属性 哪里 不存在 选择id 从资产属性 其中资产='92675e0c-7473-435f-b48e-8de1feb2164b' 或 存在 选择id 从…起 选择id 从资产属性 其中资产='92675e0c-7473-435f-b48e-8de1feb2164b' 按创建的描述、id排序 限制1 最新 哪里 id='fc114de7-93a2-44dc-be5c-92999caa0eb0'-处理开始时最新资产属性的id 返回id、已创建、资产、属性;
一种简单的方法是在插入的WHERE条件中包括最近条目的ID和最近条目的条件。 这可以在EXISTS子句中完成,该子句在且仅当ID仍然是最新条目时计算为TRUE


要使此方案起作用,必须在插入后立即提交。

我将通过向资产表添加当前的\u assets\u attributes\u id一举两得

然后,我将使用资产行作为锁,如下所示:

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;
处理伪代码:

修改检索到的属性 插入新的资产属性记录返回id 更新资产集当前\u资产\u属性\u id=yyy,其中id=xxx 提交或回滚,从而释放锁 试图修改同一资产的其他进程将在选择上阻塞。更新


这也可以在不将当前\u assets\u attributes\u id添加到assets表的情况下工作,只要使用select。其中id=xxx。用于更新资产,因为锁不关心您是否实际执行更新,并且会阻止任何其他进程锁定该行,直到拥有锁的事务结束。

这不是一种悲观的锁定模式吗?@sdgfsdh是的,它是。进程中没有执行update语句这一事实使得乐观锁定非常困难。你可以探究拉尔斯布的答案,但我认为你会为了一点好处而变得更加复杂。您也可以像Laurenz Albe建议的那样使用可重复读取来放弃更新,但这需要您在事务中执行更新。我将使用显式的悲观锁定,特别是如果更新是由一个正在运行的进程处理的,而不是在多页Web流中间的某个用户来处理的。