并发 findAndModify 查询成功更新同一文档

Edd*_*die 5 java mongodb

我有一个用 Java 编写的任务工作线程,并使用 MongoDB 3.4 副本集运行许多线程,每个线程基本上都执行此操作。

  • 运行任务
  • 通过在 MongoDB 中更新该任务的文档来表明任务已完成
  • 运行查询以查看这组任务中的所有任务是否都已完成
    • 如果是,则继续下一阶段的处理
    • 否则,什么也不做

正如您可能看到的,这里存在竞争条件;多个任务可以几乎同时完成,并认为它们是最后完成的任务。我想使用 MongoDB 来确保只允许其中一个任务开始下一阶段的处理。

我有以下代码,旨在确保只有其中一项任务可以继续(我正在使用 Jongo 与 MongoDB 交互)。

Chipset modified = chipsets
  .findAndModify("{_id: #, status: {$ne: #}}", new Object[] { chipset.getId(), Chipset.Status.Queued })
  .with("{$set: {status: #}}", new Object[] { Chipset.Status.Queued })
  .returnNew().as(Chipset.class);

if (modified != null)
    runNextProcessingStep();
Run Code Online (Sandbox Code Playgroud)

这里很简单;我只是使用 findAndModify 将芯片组(任务集)的状态更改为“已排队”。成功进行更改的人将执行 runNextProcessingStep()。

或者我认为这应该是这样的。实际上,有几个任务,即使是相隔 2 秒完成的任务,也会以某种方式返回非 null modified。据我了解,MongoDB 应该在运行 findAndModify 时锁定文档,以便非空文档只能返回一次。

我已经通过findAndModify阅读了线性化读取并实现了其中所说的所有内容。我已将连接写入关注点设置为“多数”,将读取关注点设置为“线性化”。我在 _id 和 status 上创建了一个唯一的复合索引。依然没有。也许我误解了 findAndModify 的实际行为?我究竟做错了什么?

Edd*_*die 1

好吧,这很尴尬,但为了成为一名优秀的互联网公民,我将更新所发生的事情。还有另一个线程正在从我下面改变状态。我说服自己事实并非如此,但是,并发有时确实很痛苦。findAndModify 的工作原理与我想象的完全一样。