【问题标题】:how to upsert a mongodb document/record with self generated _id in multiple thread scenario如何在多线程场景中使用自生成 _id 插入 mongodb 文档/记录
【发布时间】:2019-07-11 07:24:59
【问题描述】:

我在一个场景中使用了mongodb,许多线程可能会在DB中插入/更新文档/记录。_id是通过组合所有要插入或更新的_id标识的文档中的字段来构造的。我使用了如下的java代码。我预计在多线程场景中,如果记录/文档不存在,任何线程都可以插入带有_id和线程特定列/字段的新记录/文档,在记录可用后,任何线程都可以更新其线程特定列/字段。但是在测试中,如果记录已经可用,会报错,重复的_id已经可用,但我只将_id放在Filter中而不是在文档中设置。为了解决这个问题,我必须添加一个分布式锁(redis)或捕获 _id 重复异常并在 upsert 设置为 false 的情况下进行更新,但这两者中的任何一个都不是那么整洁,并且都会对超过 100 毫秒的性能产生严重影响。有哪位 mongodb 专家可以帮我解决这个问题?

String rkValue = (String) newObjFromRow;
Bson rkFilter = Filters.eq(rkName, rkValue);
Document document = MyMongoRow.toDocument(row, groupByGuidTsList, groupByGuidTsIndexList);
Document wrappedUpdate = new Document();
wrappedUpdate.put("$set", updateDoc);
updateOneDocWNCompare(rkFilter, MongodbConstants.methodSetOnInsert, document, true);
UpdateOptions options = new UpdateOptions();
options.upsert(true);
collection.updateOne(rkFilter, wrappedUpdate, options);

【问题讨论】:

  • 我的首要任务是使用批处理或同步。
  • 谢谢你的回复,anton,我也经常使用redis/hbase。对于这些kv风格的数据库,我的问题根本不存在,这些数据库没有插入概念。 batch 不适用于我的情况,因为每个事件都需要立即处理。而 sychronize 是为了在同一个进程中并发,我这里的线程分布在不同的主机上,所以使用分布式锁
  • 嗯,某处一定有某种同步。但无论如何,并发 upserts 有什么问题吗?
  • 如果文档/记录已经存在,会报错,重复_id已经存在
  • 但你认为它会发生还是正在发生?

标签: java multithreading mongodb concurrency upsert


【解决方案1】:

如果你检查一下,这似乎是某种期望的行为

https://jira.mongodb.org/browse/SERVER-20380

因此,为了解决这个问题,要么引入同步(甚至是分布式),要么在错误时重试 upsert。

【讨论】:

  • 它正在发生,如果在应用程序启动之前,记录/文档存在,完全没有问题。 _id 冲突异常发生在没有与特定 _id 值对应的记录/文档时,并且多个线程使用过滤器 with_id 调用 update 并且 upsert 设置为 true
  • 你分享的mongodb票我打不开,可能需要登录,我没有账号,请分享一下截图
  • 除了“正在发生”之外,我不明白您的第一条评论。但无论如何,只需重做操作,它应该会成功更新。
  • 我不知道您将不知道您将处理哪个版本的更新文档,但这是另一个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 2017-02-14
  • 2011-07-05
  • 2014-09-08
  • 2012-05-18
  • 1970-01-01
相关资源
最近更新 更多