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.