小编典典

在Postgresql中选择未锁定的行

java

有没有办法在Postgresql中选择未锁定的行?我有一个多线程应用程序可以执行以下操作:

Select... order by id desc limit 1 for update

在table。

如果有多个线程运行此查询,则它们都将尝试拉回同一行。

一个获取行锁,其他阻塞,然后在第一个更新行后失败。我真正想要的是第二个线程获取与WHERE子句匹配且尚未锁定的第一行。

为了澄清,我希望每个线程在执行选择后立即更新第一个可用行。

因此,如果有带有的行ID: 1,2,3,4,则第一个线程将进入,选择具有的行ID=4并立即对其进行更新。

如果在该事务期间有第二个线程来,我希望它与之保持联系ID=3并立即更新该行。

对于份额不会,也不符合做到这一点nowait的WHERE条款将被锁定的行匹配(ID=4 in my example)。基本上,我想要的是该WHERE子句中的“ AND NOT LOCKED” 。

Users

-----------------------------------------
ID        | Name       |      flags
-----------------------------------------
1         |  bob       |        0
2         |  fred      |        1
3         |  tom       |        0
4         |  ed        |        0

如果查询是“ Select ID from users where flags = 0 order by ID desc limit 1”并且返回一行时,下一个事物是“ Update Users set flags = 1 where ID = 0”,那么我想第一个线程用来抢行,ID 4下一个线程用来抢行ID 3。

如果我将“ For Update”添加到选择中,则第一个线程获取行,第二个线程阻塞,然后不返回任何内容,因为一旦第一个事务提交,该WHERE子句将不再满足。

如果我不使用“ For Update”,则需要在后续更新中添加WHERE子句(WHERE标志= 0),因此只有一个线程可以更新该行。

第二个线程将选择与第一个相同的行,但是第二个线程的更新将失败。

无论哪种方式,第二个线程都无法获取行并进行更新,因为我无法使数据库将第4行分配给第一个线程,将第3行分配给第二个线程,而事务却重叠了。


阅读 372

收藏
2020-11-30

共1个答案

小编典典

我的解决方案是将UPDATE语句与RETURNING子句一起使用。

Users

-----------------------------------
ID        | Name       |      flags
-----------------------------------
1         |  bob       |        0  
2         |  fred      |        1  
3         |  tom       |        0   
4         |  ed        |        0   

代替SELECT .. FOR UPDATE使用

BEGIN; 

UPDATE "Users"
SET ...
WHERE ...;
RETURNING ( column list );

COMMIT;

由于UPDATE语句在表的更新中获得了ROW EXCLUSIVE锁,因此您将获得序列化的更新。仍然允许读取,但是它们仅在UPDATE事务开始之前看到数据。

2020-11-30