FetchMode в режим на хибернация

1. Въведение

В този кратък урок ще разгледаме различни стойности на FetchMode, които можем да използваме в анотацията @ org.hibernate.annotations.Fetch .

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

Като пример ще използваме следния обект на клиента само с две свойства - идентификатор и набор от поръчки:

@Entity public class Customer { @Id @GeneratedValue private Long id; @OneToMany(mappedBy = "customer") @Fetch(value = FetchMode.SELECT) private Set orders = new HashSet(); // getters and setters }

Също така ще създадем обект за поръчка , състоящ се от идентификатор, име и препратка към клиента .

@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. FetchMode.SELECT

В нашия обект на Клиент сме отбелязали свойството на поръчките с пояснение @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=? 

В хибернация FetchMode.SELECT генерира отделна заявка за всяка поръчка , която трябва да бъде зареден.

В нашия пример това дава една заявка за зареждане на клиентите и пет допълнителни заявки за зареждане на колекцията от поръчки.

Това е известно като проблем с избора n + 1. Изпълнението на една заявка ще задейства n допълнителни заявки.

3.1. @ BatchSize

FetchMode.SELECT има опция за анотация на конфигурацията, използваща анотацията @BatchSize :

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

Hibernate ще се опита да зареди колекцията от поръчки в партиди, определени от параметъра размер .

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

Все още ще използваме същата заявка:

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

Но ще се стартира само веднъж. Сега имаме само две заявки: Една за зареждане на клиента и друга за събиране на поръчки.

4. FetchMode.JOIN

Докато FetchMode.SELECT зарежда връзките мързеливо, FetchMode.JOIN ги зарежда с нетърпение, кажете чрез присъединяване:

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

Това води до само едно запитване както за Клиента, така и за неговите Поръчки :

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

5. FetchMode.SUBSELECT

Тъй като свойството поръчки е колекция, бихме могли да използваме и FetchMode.SUBSELECT :

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

Можем да използваме SUBSELECT само с колекции.

С тази настройка се връщаме към една заявка за клиента:

Hibernate: select ... from customer customer0_ 

И една заявка за Поръчките , използвайки този път под-избор:

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

6. FetchMode срещу FetchType

Като цяло FetchMode дефинира как Hibernate ще извлича данните (чрез избор, присъединяване или подразбиране). FetchType , от друга страна, определя дали Hibernate ще зарежда данни с нетърпение или лениво.

Точните правила между тези две са както следва:

  • ако кодът не задава FetchMode , стандартният е JOIN и FetchType работи, както е дефинирано

  • с FetchMode.SELECT или FetchMode.SUBSELECT , FetchType работи също така, както е дефинирано
  • с FetchMode.JOIN набор, FetchType се игнорира и заявка винаги е нетърпелива

За допълнителна информация, моля вижте Eager / Lazy Loading In Hibernate.

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

В този урок научихме за различните стойности на FetchMode , както и как те са свързани с FetchType .

Както винаги целият изходен код е достъпен в GitHub.