Hibernate默认ID生成策略引发NonUniqueObjectException问题排查
为什么Hibernate默认ID策略会抛出NonUniqueObjectException,而IDENTITY策略正常?
这个问题的核心在于Hibernate对ID生成策略的默认行为和你代码里的ID处理方式不匹配导致的,我来给你拆解清楚:
1. 你的代码默认使用的是assigned ID生成策略
当你没有给@Id字段添加@GeneratedValue注解时,Hibernate会默认采用assigned生成策略。这个策略的核心规则是:
- 开发者必须手动为实体的ID字段赋值,Hibernate不会自动帮你生成ID
- 当调用
session.save()或entityManager.persist()时,Hibernate会认定你提供的ID是唯一且有效的
这时候只要出现以下两种情况之一,就会触发NonUniqueObjectException:
- 当前Session中已经存在一个拥有相同ID的实体对象
- 数据库对应表中已经存在一条相同ID的记录
2. GenerationType.IDENTITY解决问题的核心原因
当你切换到@GeneratedValue(strategy=GenerationType.IDENTITY)时,Hibernate会采用数据库自增ID的策略:
- 你完全不需要手动给ID字段赋值,Hibernate会让数据库(比如MySQL的AUTO_INCREMENT列、SQL Server的IDENTITY列)自动生成唯一的ID值
- 在持久化实体时,Hibernate会先插入记录,再从数据库获取自动生成的ID并赋值给实体对象
- 因为ID是由数据库保证唯一性的自增值,所以不会出现重复ID的情况,自然也就不会触发
NonUniqueObjectException
场景还原你的问题
假设你之前写了这样的代码:
Cart cart = new Cart(); cart.setId(1L); // 手动赋值ID session.save(cart); // 后续又创建了另一个ID为1的Cart对象,或者数据库里原本就有ID=1的记录 Cart anotherCart = new Cart(); anotherCart.setId(1L); session.save(anotherCart); // 这里就会抛出NonUniqueObjectException
而用了IDENTITY策略后,你不需要手动设置ID:
Cart cart = new Cart(); // 不用调用setId() session.save(cart); // Hibernate让数据库生成唯一ID,不会出现重复冲突
总结一下:你之前的代码因为用了默认的assigned策略,需要手动控制ID的唯一性,但可能出现了重复赋值的情况;而IDENTITY策略把ID生成的责任交给数据库,从根源上保证了ID的唯一性,所以解决了异常。
内容的提问来源于stack exchange,提问作者Joker
相关产品推荐
相关产品推荐

