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

PostgreSQL中的读取提交隔离级别是否会发生更新丢失?

邢永安
2023-03-14

我有一个查询如下在PostgreSQL:

UPDATE 
     queue 
SET 
  queue.status   = 'PROCESSING' 
WHERE 
    queue.status   = 'WAITING' AND
    queue.id       = (SELECT id FROM queue WHERE STATUS = 'WAITING' LIMIT 1 )
RETURNING 
        queue.id

许多工作人员试图一次处理一项工作(这就是为什么我有限制为1的子查询)。在此更新之后,每个工作人员都会获取有关id的信息并处理工作,但有时他们会获取相同的工作并处理两次或更多次。隔离级别已读提交。

我的问题是,我如何保证一个工作将被处理一次?我知道有这么多的帖子,但我可以说我已经尝试了其中的大部分,但都没有帮助();

  • 我已尝试选择更新,但它导致了死锁的情况

任何帮助都将不胜感激。

共有2个答案

云令
2023-03-14

跳过锁定可用于在PostgreSql中实现队列。看见

易超
2023-03-14

在您描述的情况下不会发生丢失的更新,但它也不会正常工作。

在上面给出的示例中,如果(假设)10个工人同时启动,所有10个工人都将执行子查询并获得相同的ID。他们都将尝试锁定该ID。其中一个工人将成功;其他人会堵住第一个人的锁。一旦第一个后端提交或回滚,其他9个后端将争夺锁。您将获得它,重新检查WHERE子句,并查看queue.status测试不再匹配,然后返回而不修改任何行。其他8个也会发生同样的情况。因此,您使用了10个查询来完成一个查询的工作。

如果您未能明确检查更新结果,并看到零行更新,您可能会认为更新丢失,但事实并非如此。由于对执行顺序和隔离规则的误解,您的应用程序中出现了一个并发错误。真正发生的一切是,您正在有效地序列化后端,以便一次只有一个后端真正取得进展。

PostgreSQL避免让它们都获得相同队列项ID的唯一方法是序列化它们,因此直到查询#1完成,它才开始执行查询#2。如果需要,可以通过LOCKing队列表来实现这一点...但是同样,您也可以只使用一个辅助角色。

你不能用咨询锁来解决这个问题,无论如何都不容易。在获得第一个可锁定项之前,使用非阻塞锁定尝试迭代队列的黑客操作会有效,但会缓慢而笨拙。

您正在尝试使用RDBMS实现工作队列。这样做不好。这将是缓慢的,它将是痛苦的,而且要做到正确和快速将是非常困难的。不要自己滚。相反,使用一个完善的、经过测试的系统进行可靠的任务排队。看看RabbitMQ、ZeroMQ、ApacheActiveMQ、Celery等。还有来自Skytools的PGQ,这是一个基于PostgreSQL的解决方案。

相关的:

  • 在PostgreSQL中,对同一个表中的不同行进行多次更新时是否存在锁定冲突?
 类似资料:
  • 基于中的评论https://www.jooq.org/doc/3.6/manual/sql-execution/transaction-management/对于Jooq来说,改变隔离级别似乎还不太可能。然而,不清楚Jooq设置的隔离级别是什么,因此我的问题是:Jooq使用的隔离级别是什么? 特别是,看起来我正在经历脏读,而我需要事务来防止这种情况。有人能确认Jooq事务阻止了脏读吗? 注意:将J

  • 在我的airflow升级到2.0.0(然后是2.0.1)并且调度程序扩展到3个节点之后,奇怪的事情发生了: DAGRUNN成功,但根本没有计划任务实例 任务失败,主机名为空(https://github.com/apache/airflow/issues/13692) 任务设置为“upstream_failed”,而上游任务成功(https://github.com/apache/airflow/

  • 本文向大家介绍Mysql事务隔离级别之读提交详解,包括了Mysql事务隔离级别之读提交详解的使用技巧和注意事项,需要的朋友参考一下 查看mysql 事务隔离级别 可以看到当前的事务隔离级别为 READ-COMMITTED 读提交 下面看看当前隔离级别下的事务隔离详情,开启两个查询终端A、B。 下面有一个order表,初始数据如下 第一步,在A,B中都开启事务 第二步查询两个终端中的number值

  • 假设我们使用自动提交模式,即:。 默认情况下(没有BEGIN),PostgreSQL以“自动提交”模式执行事务,即每个语句都在自己的事务中执行,并在语句末尾隐式执行提交(如果执行成功,否则回滚完成)。 然后,使用读取提交的隔离级别(在 postgresql 中也是缺省值),该语句是实际的隔离单元。但在这里,这句话只意味着外在的陈述?同一外部语句中嵌入的语句呢? CTE(带查询) 我测试了一些情况,

  • 下面是postgresql 9.6文档中关于读取提交隔离级别的完整段落: 读取提交是PostgreSQL中的默认隔离级别。当事务使用此隔离级别时,SELECT查询(没有FOR UPDATE/SHARE子句)只能看到查询开始前提交的数据;它永远不会看到未提交的数据或并发事务在查询执行期间提交的更改。实际上,SELECT查询会在查询开始运行时看到数据库的快照。但是,SELECT确实会看到在其自己的事务

  • 问题内容: 也许有人可以帮助我解决Spring(3.1)/ Postgresql(8.4.11)中的事务性问题 我的交易服务如下: Spring配置Webapp包含: 让我们说一个请求“ x”和一个请求“ y”同时执行并到达注释“比较”(方法insertObject)。然后,允许他们两个都插入一个新对象,并提交他们的事务。 为什么我没有RollbackException?据我所知,这就是可序列化等