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

我有一个用
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();

这里很简单;我只是使用findAndModify将芯片组(任务集)的状态更改为Queued.成功进行更改的那个将执行runNextProcessingStep().

或者这就是我认为应该如何运作的方式.实际上,几个任务,即使是相隔2秒完成的任务,也会以某种方式获得非空的修改.据我了解,MongoDB应该在运行findAndModify时锁定文档,以便可以返回非空文档不超过一次.

我已经阅读了Linearizable Reads via findAndModify并且实现了那里所说的一切.我已将连接写入问题设置为Majority,并将读取问题设置为Linearizable.我在_id和status上创建了一个唯一的复合索引.依然没有.也许我误解了findAndModify的实际行为?我究竟做错了什么?

最佳答案 嗯,这是令人尴尬的,但为了成为一个优秀的互联网公民,我会用发生的事情来更新这个.还有另一个线程正在改变我的状态.我已经说服自己这不可能是这种情况,但是,并发性有时可能是一种真正的痛苦. findAndModify完全符合我的想法.

点赞