Рубрики
Без рубрики

План выборки JPA по умолчанию

Узнайте, что такое план выборки по умолчанию JPA и чем он отличается от плана выборки запроса при использовании ассоциаций FetchType.

Автор оригинала: Vlad Mihalcea.

Вступление

В этой статье я собираюсь объяснить, что такое план выборки по умолчанию JPA и чем он отличается от плана выборки запроса при использовании FetchType ассоциаций.

Тип выборки JPA

Ассоциацию JPA можно получить лениво или нетерпеливо. Стратегия извлечения управляется с помощью атрибута fetch |/@ OneToMany , @OneToOne , @ManyToOne или @ManyToMany .

Атрибут fetch может быть либо FetchType.ЛЕНИВЫЙ или Тип выборки.НЕТЕРПЕЛИВЫЙ . По умолчанию @OneToMany и @ManyToMany ассоциации используют Тип выборки.ЛЕНИВАЯ стратегия, в то время как @OneToOne и @ManyToOne используют Тип выборки.Вместо этого СТРЕМИТЕСЬ к стратегии.

Как я объяснил в этой статье , Тип выборки.НЕТЕРПЕЛИВАЯ стратегия ужасна по умолчанию. Никогда в своей жизни я не видел хорошего варианта использования, который требовал бы ассоциации для использования FetchType.НЕТЕРПЕЛИВЫЙ стратегия. Это связано с тем, что маловероятно, что каждый возможный вариант использования в бизнесе потребует извлечения данной ассоциации, и тот факт, что Hibernate не может переопределить тип FetchType.НЕТЕРПЕЛИВАЯ стратегия с типом выборки.ЛЕНИВЫЙ во время выполнения запроса.

План Выборки По Умолчанию

У каждой сущности есть план выборки по умолчанию, заданный стратегиями выборки, настроенными во время сопоставления. Например, следующая сущность Комментарий к сообщению имеет ассоциацию сообщение , которая использует тип выборки по умолчанию .НЕТЕРПЕЛИВАЯ стратегия, данная @ManyToOne аннотацией.

@Entity(name = "PostComment")
@Table(name = "post_comment")
public class PostComment {

    @Id
    private Long id;

    @ManyToOne
    private Post post;

    private String review;
    
    //Getters and setters omitted for brevity
}

При извлечении Комментария к сообщению сущности с помощью метода найти :

PostComment comment = entityManager.find(PostComment.class, 1L);

Будет использоваться план выборки по умолчанию, и будет добавлено ЛЕВОЕ СОЕДИНЕНИЕ , чтобы гарантировать, что сообщение ассоциация будет извлечена с нетерпением:

SELECT pc.id AS id1_1_0_,
       pc.post_id AS post_id3_1_0_,
       pc.review AS review2_1_0_,
       p.id AS id1_0_1_,
       p.title AS title2_0_1_
FROM post_comment pc
LEFT OUTER JOIN post p ON pc.post_id = p.id
WHERE pc.id = 1

План выборки запроса

Однако, если вы извлекаете объект с помощью запроса JPQL:

PostComment comment = entityManager.createQuery("""
    select pc
    from PostComment pc
    where pc.id = :id
    """, PostComment.class)
.setParameter("id", 1L)
.getSingleResult();

Затем план выборки по умолчанию переопределяется планом выборки запроса, поэтому выполняются два запроса вместо одного:

SELECT pc.id AS id1_1_,
       pc.post_id AS post_id3_1_,
       pc.review AS review2_1_
FROM post_comment pc
WHERE pc.id = 1

SELECT p.id AS id1_0_0_,
       p.title AS title2_0_0_
FROM post p
WHERE p.id = 1

Запрос явно определяет план выборки, поэтому план выборки по умолчанию переопределяется. Однако ассоциация, которую необходимо быстро извлечь, все равно будет извлечена до возврата набора результатов запроса, и именно поэтому вторичные запросы выполняются для FetchType.НЕТЕРПЕЛИВЫЕ ассоциации при выполнении JPQL, API критериев или собственного SQL-запроса, который извлек объекты.

Вот почему FetchType.НЕТЕРПЕЛИВЫЙ – это опасное отображение. Это заставляет вас использовать JOIN FETCH во всех ваших запросах, которые извлекают сущность, содержащую Тип выборки.НЕТЕРПЕЛИВЫЙ ассоциация.

Вывод

План выборки JPA по умолчанию-это тот, который вы предоставляете при сопоставлении своих сущностей. Запросы переопределяют план выборки по умолчанию и предоставляют свой собственный план.

Однако, в то время как FetchType.ЛЕНИВЫЕ ассоциации могут быть быстро извлечены во время выполнения запроса с помощью директивы JOIN FETCH , FetchType.НЕТЕРПЕЛИВЫЕ ассоциации не могут быть извлечены лениво, так как вторичные запросы всегда будут выполняться, чтобы гарантировать, что Тип выборки.НЕТЕРПЕЛИВЫЕ ассоциации всегда инициализируются.