Spring mongorepository save 抛出重复键异常

问题描述 投票:0回答:5

我正在使用java和Spring。作为测试,我通过 id 查询一个对象,然后尝试保存同一对象而不更新任何内容。当我这样做时,我得到了重复的键异常。根据我读到的内容,如果 _id 为 null,MongoRepository.save() 应该执行插入操作,否则执行更新操作。显然,我应该得到更新。

一些代码:

// Succeeds
Datatype sut = mongoRepository.findOne("569eac0dd4c623dc65508679");  

// Fails with duplicate key.
mongoRepository.save(sut);  

为什么?对其他类的对象重复上述操作,它们就可以工作了。我该如何解决这个问题?我不知道如何分解它并隔离问题。

谢谢

错误:

27906 [http-bio-8080-exec-3] 2016-05-02 13:00:26,304 DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver -

Resolving exception from handler 
[
  public gov.nist.healthcare.tools.hl7.v2.igamt.lite.web.DatatypeSaveResponse 
gov.nist.healthcare.tools.hl7.v2.igamt.lite.web.controller.DatatypeController.save(
  gov.nist.healthcare.tools.hl7.v2.igamt.lite.domain.Datatype) 
throws gov.nist.healthcare.tools.hl7.v2.igamt.lite.web.exception.DatatypeSaveException
]:
org.springframework.dao.DuplicateKeyException: {
   "serverUsed" : "127.0.0.1:27017" ,
   "ok" : 1 ,
   "n" : 0 , 
   "err" : "E11000 duplicate key error index: igl.datatype.$_id_ dup key: { : ObjectId('569eac0dd4c623dc65508679') }" ,
   "code" : 11000};
nested exception is com.mongodb.MongoException$DuplicateKey: {
  "serverUsed" : "127.0.0.1:27017" ,
  "ok" : 1 ,
  "n" : 0 ,
  "err" : "E11000 duplicate key error index: igl.datatype.$_id_ dup key: { : ObjectId('569eac0dd4c623dc65508679') }" ,
  "code" : 11000}

...重复

我刚刚有了一个发现。当如上所示保存时,spring 会尝试插入,即使 _id 已填充。

当保存其他对象时(未显示,但类似),spring 执行更新,并且 _id 再次填充。

为什么有区别?文档说 spring 应该在填充 _id 时更新,并在未填充时插入。

还有其他原因可能导致这种情况吗?我的对象中有什么东西?也许是我的读取转换器?

更新: 我刚刚和团队见面。经过仔细检查,我们确定不再需要读取转换器。问题通过其他方式解决。

java spring mongodb duplicates
5个回答
7
投票

就我而言,问题是我添加了数据模型类的版本。

@Version
private Long version;

旧文档没有,它解析为 null,MongoTemplate 判定这是一个新文档。

在这种情况下,只需使用默认值初始化版本(private Long version = 0;)。


2
投票

当使用读转换器或写转换器时,您可以通过确保要保存的对象包含非空 id 字段来解决问题。

SimpleMongoRepository 在执行转换之前检查实体是否是新的。在我们的实例中,我们有一个没有 id 字段的对象,写入转换器会添加它。

向对象添加填充的 id 字段会通知 SimpleMongoRepository 调用 save 而不是 insert。

决定发生在这里。您的代码可能会因 Spring 版本而异。我希望这有帮助。

@Override
public <S extends T> S save(S entity) {

    Assert.notNull(entity, "Entity must not be null!");

    if (entityInformation.isNew(entity)) {
        return mongoOperations.insert(entity, entityInformation.getCollectionName());
    }

    return mongoOperations.save(entity, entityInformation.getCollectionName());
}

0
投票

在数据库端,您可能已经创建了唯一索引。请查看“https://docs.mongodb.com/manual/core/index-unique/”了解更多信息。


0
投票

在 Datatype 实体中实现 equals 和 hashcode 方法,并确保 mongoRepository 扩展 CrudRepositor (如https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories中所述)以确保如果对象相等,则 save 方法应合并它们而不是保存一个新的。


0
投票

我有类似的经历,

save()
正在抛出
DuplicateKeyException
,即使我只是修改了一些字段并在修改后的版本上调用了保存。就我而言,问题是我的
@Id
字段是
long
而不是
Long

© www.soinside.com 2019 - 2024. All rights reserved.