渴望获取 - 查找与 JPQL

Eager fetching - find vs JPQL

我在两个实体之间有一对一的关系 - 学生和地址。

//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();

不触发急切获取地址:

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

为什么会出现这种差异?

您在 documentation 中看到的行为。

If you are using an entity query that does not contain a JOIN FETCH directive Hibernate uses a secondary select.

This is because the entity query fetch policy cannot be overridden, so Hibernate requires a secondary select to ensure that the EAGER association is fetched prior to returning the result to the user.

If you forget to JOIN FETCH all EAGER associations, Hibernate is going to issue a secondary select for each and every one of those which, in turn, can lead to N+1 query issues.

For this reason, you should prefer LAZY associations.

因此,您可以通过以下方式修复您的查询:

entityManager.createQuery(
  "select s from Student s left join fetch s.address where s.id = :id",
   Student.class
)
.setParameter("id", id)
.getSingleResult()