数据库如何仅针对具有特定值的特定INSERT锁定表?

时间:2016-07-30 12:26:02

标签: sql database postgresql concurrency locking

是否有一种锁定表的方式,指定只应阻止具有特定值的插入? 例如,我有表“任务”和表“子任务”我需要一个操作,当任务关闭时,也应关闭与其相关且仍然打开的子任务。所以我想:

  1. 开始交易
  2. 锁定表子任务但仅阻止可以执行具有给定任务ID的插入
  3. 关闭所有子任务
  4. 使用乐观锁关闭任务(如果任务版本已更改,则执行所有回滚)
  5. 提交交易
  6. 是否可以执行我在步骤2中描述的操作?如果不是(或者如果有更好的方法),我怎样才能在这种情况下获得安全的并发?

2 个答案:

答案 0 :(得分:1)

最好的方法是自己创建一行!但您可以在交易结束时删除它。这是怎么回事

CREATE OR REPLACE FUNCTION ....
AS $$

    BEGIN

       INSERT INTO subtasks VALUE(pk, ...) ON CONFLICT (id) DO NOTHING;
       GET DIAGNOSTICS inserted = ROW_COUNT

       if inserted THEN
           DELETE from subtasks where pk = id
       endif;
    COMMIT;
$$ LANGUAGE plpgsql;

请注意,在上面的代码中INSERT ON CONFLICT实际上并未对现有数据进行任何更改。它将返回更改的行数。如果没有更改行,则插入的变量将保持为零。

这里发生的事情是,在您的交易中插入了记录,任何其他连接都无法保存相同的记录。您可以通过使用psql打开与数据库的连接来确认这一点。然后做

begin;
   insert ...

   # just wait here
commit;

而在另一个中,尝试相同的插入,你会看到它挂起。插入是否成功取决于您是在第一个psql连接中提交还是回滚。

答案 1 :(得分:0)

您无法锁定特定值的表格,但在您的情况下,此解决方案将适用:在子任务中插入时创建触发器,并在此触发器中检查相应的任务是否已关闭。如果任务已关闭,则不允许插入。

任务关闭后,任务上的另一个触发器将关闭所有相应的子任务。