有没有办法在Postgresql中选择未锁定的行?我有一个多线程应用程序可以执行以下操作:
Select... order by id desc limit 1 for update
在table。
如果有多个线程运行此查询,则它们都将尝试拉回同一行。
一个获取行锁,其他阻塞,然后在第一个更新行后失败。我真正想要的是第二个线程获取与WHERE子句匹配且尚未锁定的第一行。
为了澄清,我希望每个线程在执行选择后立即更新第一个可用行。
因此,如果有带有的行ID: 1,2,3,4,则第一个线程将进入,选择具有的行ID=4并立即对其进行更新。
1,2,3,4
ID=4
如果在该事务期间有第二个线程来,我希望它与之保持联系ID=3并立即更新该行。
对于份额不会,也不符合做到这一点nowait的WHERE条款将被锁定的行匹配(ID=4 in my example)。基本上,我想要的是该WHERE子句中的“ AND NOT LOCKED” 。
nowait
(ID=4 in my example)
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行分配给第二个线程,而事务却重叠了。
我的解决方案是将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事务开始之前看到数据。