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

Lock for SELECT so another process doesn't get old data

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

在我看来,可能有这样一种情况,线程 1 和线程 2 都在彼此的微秒内执行 select,并且都看到该行处于状态 1,然后都执行同样的事情,在释放锁后发生 2 次更新。

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

我调查了行锁定,但它说你不能阻止 select 语句,这听起来对我这里的情况不起作用。使用咨询锁是我唯一的选择吗?

你要的是比较普通的SQLSELECT ... FOR UPDATE。 Postgres 特定的文档是 here.

使用 SELECT FOR UPDATE 将在事务范围内锁定 selected 记录,让您有时间在另一个线程可以 select.

之前更新它们

您的问题引用了未知来源:

I looked into row locking, but it says you cannot prevent select statements which sounds like it won't work for my condition here. Is my only option to use advisory locks?

The official documentation on the matter:

Row-level locks do not affect data querying; they block only writers and lockers to the same row.

并发尝试不仅会 select,还会尝试使用 SELECT ... FOR UPDATE 取出相同的行级锁 - 这会导致它们等待任何先前在同一行上持有锁的事务提交或回滚。正是你想要的。

但是,许多用例在 9.5 之前的版本中使用 advisory locks 可以更好地解决。为了安全起见,您仍然可以使用 FOR UPDATE 锁定正在处理的行。但是如果下一个事务只是想处理"the next free row"通常much更高效不等待同一行,这几乎是释放锁后肯定不可用,但立即跳到"next free"。

在 Postgres 9.5+ 中考虑 FOR UPDATE SKIP LOCKED for this. Like ,这可以在很大程度上取代咨询锁。

关于同一性能猪的相关问题:

  • Function taking forever to run for large number of records

咨询锁的解释和代码示例或 Postgres 9.5+ 中的 FOR UPDATE SKIP LOCKED

一次锁定多行:

  • How to mark certain nr of rows in table on concurrent access