尽管没有重叠,Mongo DuplicateKey错误

时间:2014-01-20 20:06:26

标签: java mongodb

我在F5负载均衡器(专业管理,它没有向> 1主机发送流量)后面有一个记录良好的多个Java服务器池,运行Tomcat并安装了我的应用程序,连接到分片的mongo集群。我使用主要自然键的base64编码SHA-1哈希作为_id。当要创建新记录时,我会做一个非常基本的记录:

BasicDBObject query = new BasicDBObject();
query.put("userId", userId);
query.put("_id", id);
DBObject user = getUsersCollection().findOne(query);

if (user == null) {
  getUsersCollection().insert(new UserObject(userId));
}

这是简化的。实际上,对此用户的预先存在进行多次检查,包括应该抛出自定义异常的一个,并且不会触发任何一个。流量日志表示单个传入创建请求,以下是发生的事情的示例:

2014-01-19 20:03:45,167  [http-bio-7950-exec-827]:[...] : ERROR FATAL [...] - Internal server error
[...]: com.mongodb.MongoException$DuplicateKey: { "serverUsed" : "[...]" , "singleShard" : "replicaset_2/host1:27017,host2:27017,host3:27017" , "err" : "E11000 duplicate key error index: Users.$_id_  dup key: { : \"HASH\" }" , "code" : 11000 , "n" : 0 , "lastOp" : { "$ts" : 1390190614 , "$inc" : 1} , "connectionId" : 335764 , "ok" : 1.0}

然而,在我的Users集合中,已创建记录:

db.Users.findOne({_ ID: “HASH”}):

{
  "_id" : "HASH",
  "createDate" : ISODate("2014-01-20T04:03:45.161Z"),
  ...
}

由于时间戳的原因,我认为这很重要。我们有一个时区问题,但除此之外我将6ms差异解释为mongo集群和我的应用服务器之间的时钟偏差。此传入流量没有其他记录(并且它在服务器之间反弹时记录,甚至 - 没有别的!)所以我99.999%确信我的SINGLE LEGITIMATE插入调用是插入并抛出错误。

任何有关如何/为何如此发生的理论都将受到高度赞赏。如果需要回答有关更多信息的问题,我会运行跟踪器和示例。

1 个答案:

答案 0 :(得分:0)

您正在搜索同时使用_iduserId字段的用户。尝试注释掉这一行:query.put("_id", id);

在您的代码中不清楚Java变量userId来自何处。还不清楚UserObject如何设置_id

总体而言,它看起来像您搜索用户的方式以及您创建他的方式不匹配,即在该用户上定义唯一键的内容。

一个修复可以替换这些行:

query.put("userId", userId);
query.put("_id", id);

使用:

query.put("_id", userId);

要使_id字段成为您的userId