You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot MongoDB审计出现重复键错误求助

Spring Boot集成MongoDB审计时更新操作触发DuplicateKeyException错误解决

在Spring Boot集成MongoDB审计功能(自动维护createdDate和lastModifiedDate)时,执行更新操作触发以下重复键错误:

org.springframework.dao.DuplicateKeyException: Write operation error on server user.domain.com:27017. Write error: WriteError{code=11000, message='E11000 duplicate key error collection: springboot.category index: id dup key: { _id: "21" }', details={}}.


问题原因

当前更新逻辑是直接创建新的CategoryMongo实例并设置已存在的_id(即category_id),然后调用save()方法。Spring Data MongoDB的save()默认逻辑:

  • 若实体是瞬时状态(未从数据库加载、不在持久化上下文管理中),即使设置了_id,也会执行插入操作而非更新;
  • 只有实体是从数据库查询得到的持久化状态实例时,save()才会触发更新操作。

因此用新实例设置已存在的_id并调用save(),MongoDB会尝试插入重复_id的文档,触发11000错误。

另外,实体类中手动重写的getEmberId()方法返回category_id,与字段emberId定义不符,可能导致序列化/实体状态判断异常,间接影响save方法行为。


解决方案

1. 修正更新逻辑,使用持久化实体操作

不要直接创建新实例,先通过ID查询数据库中的实体,修改属性后再保存:

// 正确的更新逻辑
Optional<CategoryMongo> existingCatOpt = categoryRepositoryMongo.findById(category.getCategory_id().toString());
if (existingCatOpt.isPresent()) {
    CategoryMongo catm = existingCatOpt.get();
    // 修改需要更新的属性
    catm.setName(category.getName());
    catm.setSlug(category.getSlug());
    catm.setActive(category.getActive());
    // 调用save执行更新(此时为持久化状态,触发update操作)
    categoryRepositoryMongo.save(catm);
} else {
    // 若不存在,执行插入逻辑
    CategoryMongo catm = new CategoryMongo();
    catm.setName(category.getName());
    catm.setSlug(category.getSlug());
    catm.setActive(category.getActive());
    catm.setCategory_id(category.getCategory_id().toString());
    catm.setEmberId(category.getCategory_id().toString());
    categoryRepositoryMongo.save(catm);
}

2. 修正实体类getEmberId()逻辑

如果emberId需要映射为category_id,建议通过注解实现,而非重写getter:

@Getter 
@Setter 
@NoArgsConstructor
@Document(collection = "category")
public class CategoryMongo extends AuditMetadata{
    @Id
    @JsonProperty("category_id")
    private String category_id;
    
    // 若emberId需要与category_id保持一致,直接通过getter映射
    @JsonProperty("id_colletion")
    public String getEmberId() {
        return category_id;
    }

    @JsonProperty("category_name")
    private String name;

    @JsonProperty("category_active")
    private ProductEnum active = ProductEnum.ativo;

    @JsonProperty("category_slug")
    private String slug;
}

3. 确保@Version字段正常工作(可选)

审计基类中的@Version用于乐观锁,更新时需使用从数据库查询的实体(自然包含version值),避免乐观锁失效。


验证要点

  • 确认数据库category集合的_id类型与实体类category_id类型一致(均为字符串);
  • 更新操作必须基于从数据库查询得到的实体实例进行。

内容的提问来源于stack exchange,提问作者Rafael Souza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 14:05:23