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

Spring Boot集成MongoDB出现DuplicateKeyException问题求助

解决Spring Boot + MongoDB插入第二个文档时的DuplicateKeyException问题

这个问题我遇到过,核心原因是你的实体类中@Id字段的类型和默认值导致了重复键冲突,我来给你拆解一下并提供解决方案:

问题根源分析

从异常信息可以明确看到:

com.mongodb.DuplicateKeyException: Write failed with error code 11000 and error message 'E11000 duplicate key error collection: Football_Admin.SignUp index: _id dup key: { : 0 }'

这说明你两次插入的文档_id值都是0,违反了MongoDB对_id字段的唯一索引约束。

看你的SignUp实体类:

@Id
private int id;

int类型的默认值是0,当你插入第一个文档时,如果没有显式设置id,MongoDB就会把0作为_id存储;插入第二个文档时,新创建的SignUp对象id依然是默认的0,自然触发重复键错误。

解决方案(推荐第一种)

方案1:让MongoDB自动生成唯一_id(最省心)

MongoDB原生支持自动生成全局唯一的ObjectId,Spring Data MongoDB可以直接适配这个特性,只需要修改实体类的id类型:

修改后的SignUp实体类:

package com.admin.Model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection="SignUp")
public class SignUp {
    @Id
    private String id; // 把int改成String类型,MongoDB会自动生成ObjectId字符串
    private String fullName;
    private String email;
    private String password;

    // 对应修改getter和setter为String类型
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    // 其他getter/setter保持不变
    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String toString() {
        return id + "" + fullName + "" + password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

你的SignUpRepository接口本来就是MongoRepository<SignUp,String>,刚好匹配修改后的id类型,不需要做任何改动。

之后每次调用repository.save(sign)时,如果sign.getId()为null,MongoDB会自动生成一个唯一的ObjectId字符串作为_id,彻底避免重复键问题。

方案2:手动维护自增int类型id(不推荐并发场景)

如果一定要用int类型的id,你需要自己保证每次插入的id唯一,比如查询当前最大id后加1:

  1. 先在SignUpRepository中添加查询最大id的方法:
package com.admin.Repository; 

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import com.admin.Model.SignUp; 
import java.util.Optional;

@Repository 
public interface SignUpRepository extends MongoRepository<SignUp,String>{ 
    @Query(value = "{}", sort = "{id: -1}")
    Optional<Integer> findMaxId();
}
  1. 在Controller的addAdmin方法中设置唯一id:
@RequestMapping(value = "/addadmin", method = RequestMethod.POST)
public String addAdmin(@ModelAttribute("SignUp") SignUp sign) throws NoSuchAlgorithmException,InvalidKeySpecException { 
    String originalPassword = sign.getPassword(); 
    String generatedSecuredPasswordHash = generateStorngPasswordHash(originalPassword); 
    String email = sign.getEmail(); 
    String fullname = sign.getFullName(); 

    try { 
        // 手动生成唯一id
        Optional<Integer> maxId = repository.findMaxId();
        int newId = maxId.orElse(0) + 1;
        sign.setId(newId);
        
        sign.setEmail(email); 
        sign.setFullName(fullname); 
        sign.setPassword(generatedSecuredPasswordHash); 
        repository.save(sign); 
    } catch (DuplicateKeyException e) { 
        e.printStackTrace(); 
    } 

    // 其他打印代码不变
    System.out.println(generatedSecuredPasswordHash); 
    System.out.println("Email name is:"+sign.getEmail()); 
    System.out.println("Full Name is:"+sign.getFullName()); 
    System.out.println("Password is:"+sign.getPassword()); 
    return "welcome"; 
}

⚠️ 注意:这种方式在高并发场景下可能出现多个请求同时拿到相同的maxId,导致重复键问题,所以只适合低并发的小型应用。

额外注意事项

如果你的MongoDB集合中已经存在_id为0的文档,需要先删除该文档或者修改它的_id值,否则即使修改了代码,第一次插入还是会触发重复键错误。

内容的提问来源于stack exchange,提问作者FIFA oneterahertz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:08:29