锁定 SELECT,这样另一个进程就不会获取旧数据

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

我有一个表,可以有两个线程从中读取数据。如果数据处于某种状态(假设状态 1),那么该过程将执行某些操作(与此问题无关),然后将状态更新为 2。

在我看来,可能存在这样一种情况:线程 1 和线程 2 都在彼此相隔几微秒内执行选择,并且都看到该行处于状态 1,然后都执行相同的操作,并且在锁定后发生 2 次更新已被释放。

问题是:有没有办法防止第二个线程能够在 Postgres 中修改此数据 - 也就是在第一个线程的锁被释放以进行更新后,它被迫执行另一个

SELECT
,因此它知道要放弃为了防止受骗?

我研究了行锁定,但它说你无法阻止 select 语句,这听起来似乎不适用于我的情况。使用咨询锁是我唯一的选择吗?

postgresql concurrency locking postgresql-9.3
2个回答
9
投票

您的问题,引用来源不明:

我研究了行锁定,但它说你无法阻止选择 听起来这对我这里的情况不起作用的陈述。是 我使用咨询锁的唯一选择?

有关此事的官方文档:

行级锁不影响数据查询;他们只阻止作家和储物柜到同一行。

并发尝试不仅会选择,还会尝试使用

SELECT ... FOR UPDATE
取出相同的行级锁 - 这会导致它们等待任何先前持有同一行锁的事务来提交或回滚。正是您想要的。

但是,许多用例可以通过 咨询锁更好地解决 - 在 9.5 之前的版本中。为了安全起见,您仍然可以使用

FOR UPDATE
锁定正在处理的行。但是,如果下一个事务只想处理“下一个空闲行”,那么不等待同一行通常会更高效,因为锁释放后几乎肯定不可用,而是跳到“下一个空闲行” “立即。 在 Postgres 9.5+ 中请考虑使用

FOR UPDATE SKIP LOCKED

。就像

@Craig评论的那样
,这可以在很大程度上取代咨询锁。 参见:

函数需要永远运行大量记录

Postgres 更新...限制 1

如何在并发访问时标记表中的某些行

  • 您想要的是相当常见的 SQL
SELECT ... FOR UPDATE

2
投票
here


使用 SELECT FOR UPDATE 将锁定事务范围内选定的记录,以便您有时间在另一个线程选择之前更新它们。


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