无CascadeType配置时Hibernate为何检查懒加载ManyToOne关联对象的version值
问题原因说明
这个检查逻辑和@ManyToOne的级联配置没有任何关系,本质是Hibernate对关联对象状态的校验逻辑导致的,具体原因如下:
- 你保存
ExceptionMapping时,Hibernate需要先校验你关联的Supplier是合法的持久态/游离态实例,否则无法在数据库中建立外键关联。你没有配置级联,只是代表Hibernate不会自动帮你保存/更新Supplier对象,不代表不需要校验关联对象的合法性。 - 你的
Supplier实体继承了BaseEntity,其中version字段同时加了@Version和@NotNull注解。Hibernate对带乐观锁注解@Version的实体有固定的状态判断逻辑:只要version字段为null,不管主键id是否有值,都会直接判定该实体为瞬态(未持久化的新对象)。你从REST接口拿到的Supplier对象只有id值,version为null,因此被Hibernate判定为瞬态实例,触发了瞬态对象不能直接关联的报错。 - 手动将version设置为0后,符合持久化实体的version初始值规则,Hibernate会将其判定为游离态实例,允许直接关联,因此报错消失。
推荐解决方案
- 规范做法:不直接用实体类接收REST接口参数,单独定义DTO接收参数,保存时先根据DTO传递的supplierId从数据库查询得到持久态的
Supplier对象,再赋值给ExceptionMapping后执行保存,既可以避免该问题,也能防止前端非法参数篡改实体其他字段。 - 临时兼容方案:如果业务场景允许跳过乐观锁校验,可以在保存
ExceptionMapping前,手动给关联的Supplier对象的version字段设置初始值0,但是该做法存在丢失乐观锁更新校验的风险,不建议在核心业务场景使用。
内容的提问来源于stack exchange,提问作者Amir Azizkhani
相关产品推荐
相关产品推荐

