当前位置: 首页 > 知识库问答 >
问题:

Postgreql FOR UPDATE跳过锁定仍然选择重复的行

尉迟冯浩
2023-03-14

我使用PostgreSQL作为作业队列。以下是检索作业并更新其状态的查询:

        UPDATE requests AS re
        SET
          started_at = NOW(),
          finished_at = NULL
        FROM (
          SELECT
            _re.*
          FROM requests AS _re
          WHERE
            _re.state = 'pending'
          AND
            _re.started_at IS NULL
          LIMIT 1
          FOR UPDATE SKIP LOCKED
        ) AS sub
        WHERE re.id = sub.id
        RETURNING
          sub.*

现在,我有几台机器,在每台机器上我有一个进程和几个线程,在每个线程上我有一个工人。同一进程中的所有工作人员共享一个连接池,通常有10-20个连接。

问题是,上面的查询会多次返回一些行!

我找不到任何理由。有人能帮忙吗?

更详细地说,我使用的是Python3和psycopg2。

更新:

我试过@a_horse_with_no_name的回答,但似乎不起作用。

我注意到,一个请求由两个查询检索,其中start\u在更新为:

2016-04-21 14:23:06.970897 08

2016-04-21 14:23:06.831345 08

它们只相差0.14

我想知道在这两个连接执行内部SELECT子查询时,是否两个锁都还没有建立?

更新:

更准确地说,我在一台机器上的一个进程中有200个工人(即200个线程)。

共有2个答案

黄博艺
2023-03-14

有可能在select时尚未发出锁定事务,或者在select结果就绪且update语句开始时锁丢失。您是否尝试过显式启动事务?

BEGIN;
  WITH req AS (
    SELECT id
    FROM requests AS _re
    WHERE _re.state = 'pending' AND _re.started_at IS NULL
    LIMIT 1 FOR UPDATE SKIP LOCKED
    )
  UPDATE requests SET started_at = NOW(), finished_at = NULL
  FROM req
  WHERE requests.id = req.id;
COMMIT;
咸正平
2023-03-14

还请注意,如果您不想让每个线程互相妨碍,那么每个线程都有自己的连接是很重要的。

如果应用程序使用多个执行线程,则它们不能同时共享连接。您必须显式控制对连接的访问(使用互斥)或为每个线程使用连接。如果每个线程使用自己的连接,则需要使用AT子句指定线程将使用的连接。

来自:http://www.postgresql.org/docs/9.5/static/ecpg-connect.html

如果两个线程共享同一个连接,所有类型的wierd事件都会发生。我相信你的情况就是这样。如果使用一个连接进行锁定,则使用同一连接的所有其他线程都可以访问锁定的对象。

请允许我提出另一种方法,这非常简单。使用redis作为队列。您可以简单地使用redis-py和lush/rpops方法,也可以使用python-rq。

 类似资料:
  • 问题内容: 我有一个ListView子类,当上下文操作栏(CAB)处于活动状态时,我可以对其进行选择。CAB设置为事件的回调: 很好,并且ListView可以按预期工作,当前选中的项目在触摸时保持突出显示。 当我关闭CAB时, 我希望ListView返回正常状态(即Touch模式) 。问题是,无论我尝试清除哪种方法,最后选择的项目都会无限期突出显示: 有什么建议? 问题答案: 出现此问题的主要原因

  • 这是我的伪代码: 我想问,如果条件等于“key”的行已经被删除,那么“select for update”阻止的锁是否可以自动解锁,这意味着如果另一个进程在此点进入并选择相同的“key”,它就不能被此进程阻止?

  • 我想调用一个函数时,选择的任何选项。类似于这样: 但不知何故不起作用。有人能帮忙吗。 请注意 我不想捕获更改事件,如果我选择已经选择选项,则不会触发更改事件

  • 假设我们有一个包含许多列的数据框,。我只想创建一个包含以下列的DF

  • 本文向大家介绍pandas 选择重复,包括了pandas 选择重复的使用技巧和注意事项,需要的朋友参考一下 示例 如果需要将值设置0为column B,则在columnA中的重复数据中,首先使用创建掩码Series.duplicated,然后使用DataFrame.ix或Series.mask: 如果需要反面罩使用~:            

  • 问题内容: 如何在数据库中选择一些记录,从而跳过MS Access中的行数。在MySQL中是。火鸟是等。 在Google上根本没有运气=( 问题答案: 如果您知道要跳过多少条记录,则可以执行以下操作: 然后,您可以排除不需要的记录。 如果您随后知道要返回的记录总数,则可以执行以下操作: