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

FetchMode в спящем режиме

Узнайте, как использовать FetchMode в режиме гибернации.

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

1. введение

В этом коротком уроке мы рассмотрим различные значения FetchMode , которые мы можем использовать в аннотациях @ org.hibernate.Fetch аннотация.

2. Настройка примера

В качестве примера мы будем использовать следующую сущность Customer с двумя свойствами – идентификатором и набором заказов:

@Entity
public class Customer {

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "customer")
    @Fetch(value = FetchMode.SELECT)
    private Set orders = new HashSet<>();

    // getters and setters
}

Кроме того, мы создадим объект Order , состоящий из идентификатора, имени и ссылки на Клиента .

@Entity
public class Order {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;

    // getters and setters
}

В каждом из следующих разделов мы будем извлекать клиента из базы данных и получать все его заказы:

Customer customer = customerRepository.findById(id).get();
Set orders = customer.getOrders();

3. Режим выборки.ВЫБИРАТЬ

В нашей сущности Customer мы аннотировали свойство orders с помощью аннотации @Fetch :

@OneToMany
@Fetch(FetchMode.SELECT)
private Set orders;

Мы используем @Fetch для описания того, как Hibernate должен извлекать свойство при поиске Клиента.

Использование SELECT указывает на то, что свойство должно загружаться лениво.

Это означает, что для первой строки:

Customer customer = customerRepository.findById(id).get();

Мы не увидим соединения с таблицей заказов:

Hibernate: 
    select ...from customer
    where customer0_.id=?

И это для следующей строки:

Customer customer = customerRepository.findById(id).get();

Мы увидим последующие запросы для связанных заказов:

Hibernate: 
    select ...from order
    where order0_.customer_id=?

Hibernate FetchMode.SELECT генерирует отдельный запрос для каждого Заказа , который необходимо загрузить.

В нашем примере это дает один запрос для загрузки Клиентов и пять дополнительных запросов для загрузки коллекции заказов.

Это известно как проблема выбора n + 1. Выполнение одного запроса вызовет n дополнительных запросов.

3.1. @BatchSize

FetchMode.ВЫБЕРИТЕ имеет необязательную аннотацию конфигурации, используя @BatchSize аннотацию:

@OneToMany
@Fetch(FetchMode.SELECT)
@BatchSize(size=10)
private Set orders;

Hibernate попытается загрузить коллекцию заказов пакетами, определенными параметром size .

В нашем примере у нас всего пять заказов, поэтому одного запроса достаточно.

Мы все равно будем использовать тот же запрос:

Hibernate:
    select ...from order
    where order0_.customer_id=?

Но он будет запущен только один раз. Теперь у нас есть только два запроса: один для загрузки Клиента и один для загрузки коллекции заказов.

4. FetchMode.JOIN

While FetchMode.ВЫБЕРИТЕ лениво загружает отношения, FetchMode.JOIN загружает их с нетерпением, скажем, через join:

@OneToMany
@Fetch(FetchMode.JOIN)
private Set orders;

Это приводит всего к одному запросу как для Клиента , так и для их Заказа s:

Hibernate: 
    select ...
    from
        customer customer0_ 
    left outer join
        order order1 
            on customer.id=order.customer_id 
    where
        customer.id=?

5. Режим выборки.ПОДВЫБОРКА

Поскольку свойство orders является коллекцией, мы также можем использовать FetchMode.ПОДВЫБОРКА :

@OneToMany
@Fetch(FetchMode.SUBSELECT)
private Set orders;

Мы можем использовать SUBSELECT только с коллекциями.

С этой настройкой мы возвращаемся к одному запросу для Клиента:

Hibernate: 
    select ...
    from customer customer0_

И один запрос для Order s, используя суб-выбор на этот раз:

Hibernate: 
    select ...
    from
        order order0_ 
    where
        order0_.customer_id in (
            select
                customer0_.id 
            from
                customer customer0_
        )

6. FetchMode против FetchType

В общем случае FetchMode определяет, как Hibernate будет извлекать данные (путем выбора, объединения или подзапроса). FetchType , с другой стороны, определяет, будет ли Hibernate загружать данные с нетерпением или лениво.

Точные правила между этими двумя являются следующими:

  • если код не установлен FetchMode , значение по умолчанию – ПРИСОЕДИНИТЬСЯ и FetchType работает, как определено
  • с с или или набор, FetchType также работает, как определено
  • с с набор, FetchType игнорируется, и запрос всегда нетерпелив

Для получения дополнительной информации, пожалуйста, обратитесь к Нетерпеливой/Ленивой загрузке в спящем режиме .

7. Заключение

В этом уроке мы узнали о различных значениях FetchMode , а также о том, как они связаны с FetchType .

Как всегда, весь исходный код доступен на GitHub .