Разница между JOIN и JOIN FETCH в спящем режиме

Пожалуйста, помогите мне понять, где использовать обычный JOIN и где JOIN FETCH.

Например, если у нас есть эти два запроса

FROM Employee emp
JOIN emp.department dep

и

FROM Employee emp
JOIN FETCH emp.department dep

Есть ли разница между ними? Если да, то какой из них использовать, когда?

Ответ 1

В этих двух запросах вы используете JOIN для запроса всех сотрудников, имеющих по крайней мере один связанный с ним отдел.

Но разница заключается в следующем: в первом запросе вы возвращаете только Employes for Hibernate. Во втором запросе вы возвращаете Employees и все связанные департаменты.

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

Вы можете использовать второй запрос, если уверены, что вам понадобится Департамент каждого сотрудника. Если вам не нужен отдел, используйте первый запрос.

Я рекомендую прочитать эту ссылку, если вам нужно применить какое-то условие WHERE (что вам, вероятно, понадобится): Как правильно выразить JPQL "join fetch" с "where" как JPA 2 CriteriaQuery?

Обновление

Если вы не используете fetch, и отделы продолжают возвращаться, это связано с тем, что ваше сопоставление между Employee and Department (a @OneToMany) установлено с помощью FetchType.EAGER. В этом случае любой запрос HQL (с fetch или нет) с FROM Employee будет вызывать все департаменты. Помните, что все сопоставление * ToOne (@ManyToOne и @OneToOne) по умолчанию EAGER.

Ответ 2

в эта ссылка, о которой я упомянул ранее в комментарии, читайте эту часть:

Соединение "выборки" позволяет ассоциациям или наборам значений быть инициализируются вместе с их родительскими объектами с использованием одного выбора. Это особенно полезно в случае коллекции. Это эффективно отменяет внешнее объединение и ленивые объявления файл сопоставления для ассоциаций и коллекций.

этот "JOIN FETCH" будет иметь эффект, если у вас есть свойство (fetch = FetchType.LAZY) для коллекции внутри объекта (пример ниже).

И это только эффект метода "когда запрос должен произойти". И вы также должны знать this:

hibernate имеют два ортогональных понятия: когда выбирается ассоциация и как он извлекается. Важно, чтобы вы не путали их. Мы используем выборка для настройки производительности. Мы можем использовать ленивый, чтобы определить контракт для какие данные всегда доступны в любом отдельном экземпляре конкретного класс.

когда выбирается ассоциация → ваш тип "FETCH"

как он извлекается → Присоединиться/выбрать/подзапрос/пакет

В вашем случае FETCH будет иметь эффект, только если у вас есть отдел как набор внутри Employee, что-то вроде этого в сущности:

@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;

когда вы используете

FROM Employee emp
JOIN FETCH emp.department dep

вы получите emp и emp.dep. когда вы не использовали fetch, вы все равно можете получить emp.dep, но hibernate будет обрабатывать другой выбор в базе данных, чтобы получить этот набор отделов.

так что это просто вопрос настройки производительности, о том, что вы хотите получить весь результат (вам это нужно или нет) в одном запросе (ожидание выборки) или вы хотите запросить его позже, когда вам это нужно (ленивый выбор).

Используйте целевую выборку, когда вам нужно получить небольшие данные с одним выбором (один большой запрос). Или используйте ленивую выборку, чтобы запросить то, что вам нужно в последнее время (многие более мелкие запросы).

использовать выборку, когда:

  • нет большой unneeded коллекции/набора внутри этого объекта, который вы собираетесь получить

  • связь с сервером приложений на сервере слишком далеко и требуется долгое время

  • вам может понадобиться последняя коллекция, если у вас нет доступа к ней ( вне метода <класs →

Ответ 3

Dherik: Я не уверен, что вы говорите, когда вы не используете fetch, результат будет иметь тип: List<Object[ ]>, что означает список таблиц объектов, а не список Employee.

Object[0] refers an Employee entity 
Object[1] refers a Departement entity 

Когда вы используете выборку, есть только один выбор, и результатом является список Employee List<Employee>, содержащий список отделов. Он отменяет ленивую декларацию субъекта.

Ответ 4

Если у вас есть сопоставление @oneToOne, установленное в FetchType.LAZY, и вы используете второй запрос (потому что вам нужны объекты Департамента, которые будут загружены как часть объектов Employee), что Hibernate будет делать, это будет выдавать запросы для извлечения объектов Департамента для каждого отдельный объект Employee, который он извлекает из базы данных. Позже в коде вы можете получить доступ к объектам Департамента через однозначную ассоциацию Employee to Department, а Hibernate не выдаст никакого запроса на получение объекта Department для данного Сотрудника. Помните, что Hibernate по-прежнему выдает запросы, равные количеству получаемых Работ. Hibernate выдаст такое же количество запросов в обоих выше запросах, если вы хотите получить доступ к объектам Департамента всех объектов Employee