使用@GeneratedValue(IDENTITY)为何触发Duplicate Key异常?
问题根源分析
你遇到的java.lang.IllegalStateException: Duplicate key异常,核心问题出在实体类的主键配置错误:
- 你的
JobMetadataEntity中,id字段标注了@Id和@GeneratedValue(strategy = GenerationType.IDENTITY),但注释明确说明该字段不是数据库列。 GenerationType.IDENTITY策略依赖数据库的自增列生成主键值,而这个字段不在数据库中,JPA无法为它生成唯一标识值。这就导致查询返回的多个实体可能出现相同的id值,最终调用Collectors.toMap时因为键重复抛出异常。
解决方案
1. 修正实体类主键配置(根本解决)
根据实际需求选择以下两种方式:
方式一:id仅作内存标识,无需作为JPA主键
直接移除@Id和@GeneratedValue注解,手动为id生成唯一值:
public class JobMetadataEntity implements Serializable { // 仅作为内存标识,不是DB列 private Integer id; @Column(name = "MODULE") private String module; // 实例化时手动生成唯一id,比如用AtomicInteger自增 private static final AtomicInteger ID_GENERATOR = new AtomicInteger(0); public JobMetadataEntity() { this.id = ID_GENERATOR.incrementAndGet(); } }
方式二:将id作为数据库主键
如果需要id作为JPA主键,必须让它对应数据库的自增列:
- 在数据库中为
JobMetadataEntity对应的表添加自增id列(比如MySQL的id INT AUTO_INCREMENT PRIMARY KEY); - 保留实体类的
@Id和@GeneratedValue(strategy = GenerationType.IDENTITY)注解,移除“NOT a DB Column”注释:
public class JobMetadataEntity implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(name = "MODULE") private String module; }
2. 临时规避toMap重复键异常(可选)
如果暂时无法修改实体类,可以在collect时指定重复键的处理逻辑,避免抛出异常。比如用新值覆盖旧值:
Map<Integer, JobMetadataEntity> jobMetadataEntityMap = jobMetadataRepository.findAllByModule("MODULE_NAME") .stream().collect(Collectors.toMap(e -> e.getId(), e -> e, (oldVal, newVal) -> newVal));
内容的提问来源于stack exchange,提问作者vs777
相关产品推荐
相关产品推荐

