为何@ManyToOne(FetchType.EAGER)时Hibernate执行两次SELECT查询?
问题原因与解决方案:Hibernate EAGER关联的查询差异
差异原因
Hibernate对不同类型的EAGER关联采用了不同的加载逻辑,这就是导致两种场景查询次数不同的核心原因:
- @ManyToOne 关联:对于这种类型的EAGER关联,Hibernate默认会将其合并到主查询中,通过
LEFT JOIN的方式一次性加载所有关联数据。所以当PersonEntity有两个@ManyToOne EAGER关联时,只会生成一条包含多个LEFT JOIN的SQL语句。 - @OneToOne(FetchType.EAGER) 关联:如果这个关联不是基于主键建立的,或者关联字段允许为null,Hibernate不会自动将其合并到主查询,而是会单独执行一条SELECT语句加载关联实体。这是因为Hibernate要避免@OneToOne关联可能带来的主实体数据重复问题,或是出于对关联可选性的处理逻辑,默认选择了单独查询的方式。当EmployeeEntity同时存在@OneToOne和@ManyToOne的EAGER关联时,Hibernate会先查询主实体,再单独查询@OneToOne的关联数据,因此产生两次SELECT。
解决方案:用JOIN FETCH实现单查询加载
要让EmployeeEntity的所有EAGER关联都通过单查询加载,只需在JPQL查询中显式使用JOIN FETCH指定要加载的关联:
// 修改后的查询语句,一次性加载所有关联数据 List<EmployeeEntity> employees = EmployeeEntity.find("FROM EmployeeEntity e JOIN FETCH e.person JOIN FETCH e.employeeType").list();
这样Hibernate就会生成一条包含所有JOIN的SELECT语句,一次性获取EmployeeEntity、PersonEntity和EmployeeTypeEntity的全部数据,避免多次查询的开销。
内容的提问来源于stack exchange,提问作者Juan Jose Garcia
相关产品推荐
相关产品推荐

