如何锁定表中的特定行以仅更新其中的一个?

问题描述 投票:0回答:1

我有 Postgres 13.7 数据库和一个更新 Type-2 SCD 表的进程,特别是一个使用“current_record”列来表示一行的最新版本的进程。

在此表上插入新数据和更新 current_record 列都发生在单个事务中,并且(根据触发它们的过程的性质)仅发生在与特定外键相关的一小部分记录上a 任何给定的时间。我目前遇到一个问题,如果两个更新在同一外键上彼此相隔几毫秒,则更新 current_record 列的过程会将两个记录的列设置为 True,因为两个事务都尚未完成,并且认为自己拥有最新记录。

是否可以通过对特定外键或事务本身的某种特定类型的临时行级锁来防止这种情况发生?我已经尝试查看有关此的文档,但是关于锁类型以及它们如何相互作用的大量信息让我头晕目眩。

我试过:

  • 将交易分成两部分,但问题仍然存在,因为事件之间的时间太快了
  • 创建一个手动修复问题的协调脚本(宁愿避免这种情况)
  • 创建一个约束来为每个外键强制执行单个 True current_record,但这会极大地减慢过程并且对我来说不可行
sql postgresql locking
1个回答
0
投票

在此示例中,SELECT ... FOR UPDATE 语句获取与指定外键值匹配的行的锁。任何其他尝试更新相同行的事务都将被阻止,直到第一个事务释放锁。

通过获取要更新的行的锁,您可以确保一次只有一个事务可以更新特定外键的 current_record 列。

请注意,FOR UPDATE 锁仅保留到事务结束,因此您需要确保整个更新过程包含在单个事务中。

BEGIN;

-- Acquire a lock on the rows for a specific foreign key
SELECT * FROM your_table WHERE foreign_key = <value> FOR UPDATE;

-- Update the current_record column
UPDATE your_table SET current_record = TRUE WHERE foreign_key = <value> AND 
record_id = <id>;

COMMIT;
© www.soinside.com 2019 - 2024. All rights reserved.