我在两个实体之间有一对一的关系——学生和地址。
//Student
@OneToOne(fetch = EAGER)
@JoinColumn(name = "ADDRESS_ID")
private Address address;
调用entityManager.find(Student.class, 1)
导致ADDRESS按预期被急切地提取:
Hibernate:
select
student0_.id as id1_4_0_,
student0_.address_id as address_7_4_0_,
student0_.crt_ts as crt_ts2_4_0_,
student0_.email as email3_4_0_,
student0_.first_name as first_na4_4_0_,
student0_.last_name as last_nam5_4_0_,
student0_.upd_ts as upd_ts6_4_0_,
address1_.id as id1_1_1_,
address1_.city as city2_1_1_,
address1_.state as state3_1_1_,
address1_.street as street4_1_1_,
address1_.zip as zip5_1_1_
from
t_student student0_
left outer join
t_address address1_
on student0_.address_id=address1_.id
where
student0_.id=1
但是,调用
String query = "select s from Student s where s.id=1";
return entityManager.createQuery(query, Student.class).getSingleResult();
不会触发ADDRESS:的紧急获取
Hibernate:
select
student0_.id as id1_4_,
student0_.address_id as address_7_4_,
student0_.crt_ts as crt_ts2_4_,
student0_.email as email3_4_,
student0_.first_name as first_na4_4_,
student0_.last_name as last_nam5_4_,
student0_.upd_ts as upd_ts6_4_
from
t_student student0_
where
student0_.id=1
为什么会出现这种差异?
文档中描述的行为。
如果使用的实体查询不包含
JOIN FETCH
指令,Hibernate将使用辅助选择。这是因为实体查询获取策略不能被覆盖,所以Hibernate需要一个辅助选择,以确保在将结果返回给用户之前获取EAGER关联。
如果您忘记加入FETCH所有EAGER关联,Hibernate将为每一个关联发出二次选择,这反过来会导致N+1查询问题。
出于这个原因,你应该更喜欢LAZY协会。
因此,您可以通过以下方式修复查询:
entityManager.createQuery(
"select s from Student s left join fetch s.address where s.id = :id",
Student.class
)
.setParameter("id", id)
.getSingleResult()