Spring Boot+Hibernate环境下OneToOne映射导致Parent实体重复保存问题
问题诱因
- 双向
@OneToOne关联的配置逻辑和Hibernate持久化逻辑冲突是核心原因:
你在Parent侧的@OneToOne注解设置了mappedBy = "parent",说明关联的维护方是Child实体,Parent只是反向端,同时你配置了cascade = CascadeType.ALL,保存Parent时会级联触发Child的持久化。而Child侧的@MapsId注解要求Child的主键必须复用关联Parent的主键,该规则要求Parent必须先完成持久化拿到主键,才能继续持久化Child。 - 关联绑定不完整触发重复插入:
如果你的业务代码中只给Parent实例设置了child属性,没有同步给Child实例的parent属性赋值为当前Parent对象,Hibernate处理级联保存的Child时,会检测到Child的parent字段为空,但Parent侧的关联设置了optional = false要求关联必须存在,就会误将当前Parent实例判定为未持久化的瞬时态对象,触发第二次插入操作,触发唯一索引冲突。 - Hibernate 5.5.x版本的固有逻辑问题:
该版本在处理双向@OneToOne + @MapsId + 反向端级联的组合场景时,确实存在重复触发被关联实体插入的bug,这也对应了你将Child的关联改为@Transient后,级联逻辑不再触发、插入冲突消失的现象。
临时修复方案
你可以先做以下调整验证:
- 给Parent和Child设置关联时,必须双向赋值:
parent.setChild(child); child.setParent(parent); - 将Parent侧的级联配置从
CascadeType.ALL改成仅保留必要的级联类型,或者移除级联,改为手动持久化Child - 升级Hibernate到5.6.x及以上稳定版本,修复该版本的关联持久化bug
内容的提问来源于stack exchange,提问作者Jesse van Bekkum
相关产品推荐
相关产品推荐

