一尘不染

多个事务期间的数据库行锁定

sql

我正在使用Postgresql,我需要一种方法来使工作进程锁定特定行,而该进程在该行上进行操作。它本质上是一个动作表,应该只执行一次。每个进程都应抓住不同的行进行操作。

在此“操作”过程中,工作进程将计算一些值并多次插入事务中(在计算和插入数据库之间会有所不同)。

我不知道每个操作将花费多长时间(它会有所不同),并且如果该进程死亡/被杀死或系统崩溃,我需要一种方法来解锁该行(以便其他进程可以抓住该行并完成对它的操作)
)。

据我所知,Postgresql的行锁仅在一个事务中存在。我当时想添加一些标志,该标志将指示行是否被锁定到表中,但是我很难弄清楚如何知道该行是否仍在进行操作,或者是否正在挂起,因为工作进程死了(在后一种情况下,应该由其他工作进程处理)?(我在该表中有一个完成标志来表示该行已完成/正在处理)


阅读 122

收藏
2021-05-16

共1个答案

一尘不染

使用标志的解决方案似乎可行,我认为唯一需要做的就是使锁失效。基本上,我构造锁的方式是,我将在获取锁时编写一个时间戳记,并使其成为时间戳,以便该过程在保持记录工作的同时,必须经常(即每30秒)
更新 一次锁。如果该进程终止或以其他方式无法完成工作,则锁定将过期,并且如果超过两倍的超时时间,则其他进程可以 解锁

当进程完成对记录的处理时,它将清除锁定标志并将该记录标记为已处理(再次标记)。

您可能希望有两个字段:一个将存储时间戳锁定标志,另一个将指示哪个进程拥有该锁(以防万一,您需要关心它)。我假设有某种键可用于对表中的记录进行排序,以使“下一个操作”的概念有意义。

您可以使用这样的查询来获取下一条要处理的记录:

 -- find the next available process and "lock" it by updating it's flag
 UPDATE actions_tabe
    SET LockFlag = @timestamp,
        Process = @processname
  WHERE Id IN (SELECT Id
            FROM actions_table
           WHERE LockFlag IS null
             AND IsComplete = '0'
             AND ScheduledTime < now()
           ORDER BY Scheduledtime ASC, Id ASC
           LIMIT 1);

 -- return the Id and Action of the record that was just marked above
 SELECT Id, Action
   FROM actions_table
  WHERE Process = @processname
2021-05-16