1. введение
В этом коротком уроке мы рассмотрим различные значения FetchMode , которые мы можем использовать в аннотациях @ org.hibernate.Fetch аннотация.
2. Настройка примера
В качестве примера мы будем использовать следующую сущность Customer с двумя свойствами – идентификатором и набором заказов:
@Entity public class Customer { @Id @GeneratedValue private Long id; @OneToMany(mappedBy = "customer") @Fetch(value = FetchMode.SELECT) private Setorders = 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(); Setorders = customer.getOrders();
3. Режим выборки.ВЫБИРАТЬ
В нашей сущности Customer мы аннотировали свойство orders с помощью аннотации @Fetch :
@OneToMany @Fetch(FetchMode.SELECT) private Setorders;
Мы используем @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 Setorders;
Hibernate попытается загрузить коллекцию заказов пакетами, определенными параметром size .
В нашем примере у нас всего пять заказов, поэтому одного запроса достаточно.
Мы все равно будем использовать тот же запрос:
Hibernate: select ...from order where order0_.customer_id=?
Но он будет запущен только один раз. Теперь у нас есть только два запроса: один для загрузки Клиента и один для загрузки коллекции заказов.
4. FetchMode.JOIN
While FetchMode.ВЫБЕРИТЕ лениво загружает отношения, FetchMode.JOIN загружает их с нетерпением, скажем, через join:
@OneToMany @Fetch(FetchMode.JOIN) private Setorders;
Это приводит всего к одному запросу как для Клиента , так и для их Заказа 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 Setorders;
Мы можем использовать 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 .