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

时间:2014-01-01 20:01:57

标签: sql postgresql concurrency transactions locking

嗨,新年快乐:)

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

在此'操作'期间,工作进程将计算一些值并在事务中多次插入数据库(它将在计算和插入数据库之间进行更改)。

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

据我所知,Postgresql的行锁仅在一次交易中持续存在。我正在考虑添加一些标志,这将指示行是否被锁定到表中,但是我无法确定如何判断该行是否仍在操作,或者是否挂起,因为工作进程死了(在后一种情况下,它应该由其他工人进程)? (我在该表中有一个完成的标志,表示该行已完成/已完成处理)

1 个答案:

答案 0 :(得分: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

示例小提琴:http://sqlfiddle.com/#!11/9c120/26/1