使用Hibernate保存实体时触发“重复键违反唯一约束”错误的解决
问题根源
你遇到的问题是单向@OneToMany关联时,Hibernate默认会在生成的中间表中给关联Archetype的字段添加唯一约束,导致同一个Archetype实例只能绑定到一个ArchetypeMatchUp上,完全违背你“不同对战关系共享Archetype”的需求。
解决方案
给两个@OneToMany关联分别添加@JoinTable注解,明确指定中间表结构,主动取消Hibernate自动添加的唯一约束。同时注意第二个列表的@OrderColumn要在@JoinTable里绑定对应的排序字段。
修改后的实体代码如下:
@Entity @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor public class ArchetypeMatchUp { @Id @JsonIgnore @GeneratedValue(strategy = SEQUENCE, generator = "seq_archetype_match_up_generator") @SequenceGenerator(name = "seq_archetype_match_up_generator", sequenceName = "seq_archetype_match_up") private Long id; @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true) @JoinTable( name = "archetype_match_up_first_player", joinColumns = @JoinColumn(name = "archetype_match_up_id"), inverseJoinColumns = @JoinColumn(name = "archetype_id") ) private List<Archetype> firstPlayerArchetype; @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true) @JoinTable( name = "archetype_match_up_second_player", joinColumns = @JoinColumn(name = "archetype_match_up_id"), inverseJoinColumns = @JoinColumn(name = "archetype_id"), orderColumns = @OrderColumn(name = "archetype_order") ) private List<Archetype> secondPlayerArchetype; // ... }
关键说明
@JoinTable明确指定了中间表名称、两边的外键字段:archetype_match_up_id关联ArchetypeMatchUp主键,archetype_id关联Archetype主键,Hibernate不会再给archetype_id添加唯一约束。- 第二个列表的
@OrderColumn通过orderColumns参数绑定到中间表的archetype_order字段,用来维护列表元素顺序,同时不影响关联的唯一性。 - 两个中间表分开命名,避免逻辑混淆,更贴合业务语义。
测试验证
修改后按原逻辑执行测试即可:
- 保存三个Archetype实例(如A、B、C)
- 保存第一个ArchetypeMatchUp,关联[A,B]
- 保存第二个ArchetypeMatchUp,关联[B,C]
此时不会再触发唯一约束冲突异常,同一个Archetype(如B)可被多个对战关系关联。
内容的提问来源于stack exchange,提问作者BullyWiiPlaza
相关产品推荐
相关产品推荐

