在负载测试期间,MongoDB插入时的竞态条件

3

在进行负载测试时,有时会遇到这种情况,代码如下(简化):

var person = Persons.findOne();
if(person == null){
         Persons.insert(newDocument);
}

因为插入操作与现有文档冲突,所以会引发错误 - 即使我使用了findOne()进行检查。在插入操作之前暂停时,Mongo shell 显示文档。

错误信息为:

WriteConcern detected an error ''. (Response was { "ok" : 1, "code" : 11000, "err" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: MainDB.Persons.$Person UniquePersonID dup key: { : \"BOT 878611 141152\" }", "n" : NumberLong(0) }).

唯一索引是:
{ v: 1, name: "Person UniquePersonID", key: { UniquePersonID : 1 }, unique: true, ns: "MainDB.Persons", sparse: true, dropDups: true, background: true }

这似乎是一个竞态条件,并且我正在寻找正确的解决方法:
  1. 使用$setOnInsert
  2. 使用带有Upsert标志的findAndModify
  3. 使用Replace和Upsert的Update
这些方法的问题在于1+2只替换某些字段,而我想要替换整个文档,而方法3替换整个文档,但_id发生冲突。
(如相关,我使用官方的C#驱动程序版本1.9.2.235)
感谢您的帮助。

你能否明确说明你收到了什么错误,以及你最终想要用那段代码实现什么?提供示例文档也会有所帮助。看起来你应该尝试插入文档而不进行检查,因为如果文档已存在,则会在_id上出现唯一键冲突,但根据你提供的信息很难确定。 - wdberkeley
@wdberkeley - 添加了更多细节,谢谢。 - Nir
1个回答

1

好的,如果我理解正确,您想要做以下事情:

  1. 检查是否存在具有给定UniquePersonId的文档
  2. 如果不存在,则插入具有该UniquePersonId的文档
  3. 如果这样的文档已经存在,则不执行任何操作。

您的代码遇到重复键错误是因为您认为的原因 - 在findOneinsert之间,另一个线程插入了相同的UniquePersonId。这没关系 - 错误只是告诉代码,某个其他进程已经完成了它的工作。唯一索引违规错误不是错误的意义在于某些东西没有正常工作。它只是让您知道由于您施加的唯一约束而使您的操作无效。我认为(不知道更多上下文),如果发生唯一索引错误,您可以运行插入并忽略该错误。


那么可以尝试使用类似于try{Insert();}catch{}的方式来实现。但是你的意思是没有更好的解决方法了吗? - Nir
你还能想到什么更好的存在方式吗?在我看来,这似乎完全没问题。 - wdberkeley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接