Hibernate双向@OneToOne子端LAZY加载失效问题排查
双向@OneToOne懒加载失效问题排查
我定义了两个实体:Person(人员)和Passport(护照),并将它们映射为双向@OneToOne关联,两处关联均设置为FetchType.LAZY(懒加载)。
Passport(主控端)代码
@Entity @Table(name = "passports") public class Passport { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private Integer serial; private Integer number; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "person_id", referencedColumnName = "id") private Person person; }
Person(被控端/子端)代码
@Entity @Table(name = "people") public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; @OneToOne(mappedBy = "person", fetch = FetchType.LAZY) private Passport passport; }
当仅查询Person实体时:
Person p = entityManager.find(Person.class, 1); System.out.println(p.getName());
Hibernate却生成了两条SELECT语句(预期仅查询Person表):
Hibernate: select p1_0.id,p1_0.name from people p1_0 where p1_0.id=? Hibernate: select p1_0.id,p1_0.number,p1_0.person_id,p1_0.serial from passports p1_0 where p1_0.person_id=?
预期仅执行一条查询,但实际触发了两条,请问为什么LAZY加载不生效?哪里操作有误?
原因分析
这是Hibernate双向@OneToOne关联的常见问题:被控端(标注mappedBy的一方)的FetchType.LAZY默认不生效。
因为双向OneToOne中,被控端(Person)的表没有关联字段,关联字段person_id在主控端(Passport)的表中。Hibernate为了确认person.getPassport()是否为null,会主动执行查询去Passport表校验,直接绕过了懒加载配置。
解决方案
有两种常用解决方式:
添加
@LazyToOne(LazyToOneOption.NO_PROXY)配置
在Person实体的@OneToOne注解上补充该配置,同时开启Hibernate字节码增强,就能实现真正的懒加载:@OneToOne(mappedBy = "person", fetch = FetchType.LAZY) @LazyToOne(LazyToOneOption.NO_PROXY) private Passport passport;字节码增强可通过Maven/Gradle的Hibernate插件配置开启。
改为单向关联
如果业务不需要从Person反向查询Passport,直接删除Person中的passport字段,只保留Passport到Person的单向关联,懒加载即可正常生效。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

