Пожалуйста, помогите мне понять, где использовать обычный JOIN, а где JOIN FETCH.
Например, если у нас есть эти два запроса
FROM Employee emp
JOIN emp.department dep
и
FROM Employee emp
JOIN FETCH emp.department dep
Есть ли разница между ними? Если да, какой использовать когда?
Ответы:
В этих двух запросах вы используете JOIN для запроса всех сотрудников, у которых есть хотя бы один отдел.
Но разница в следующем: в первом запросе вы возвращаете только сотрудников для Hibernate. Во втором запросе вы возвращаете сотрудников и все связанные отделы.
Таким образом, если вы используете второй запрос, вам не нужно будет делать новый запрос, чтобы снова попасть в базу данных, чтобы увидеть отделы каждого сотрудника.
Вы можете использовать второй запрос, когда вы уверены, что вам потребуется отдел каждого сотрудника. Если вам не нужен отдел, используйте первый запрос.
Я рекомендую прочитать эту ссылку, если вам нужно применить некоторое условие WHERE (что вам, вероятно, понадобится): как правильно выразить JPQL "join fetch" с предложением "where" как JPA 2 CriteriaQuery?
Обновить
Если вы не используете
fetch
и Департаменты продолжают возвращаться, это потому, что для вашего отображения между Сотрудником и Отделом (а@OneToMany
) установлено значениеFetchType.EAGER
. В этом случае любой HQL-fetch
запрос (с или без)FROM Employee
принесет все отделы. Помните, что все сопоставления * ToOne (@ManyToOne
и@OneToOne
) по умолчанию являются EAGER.источник
fetch
это нужно использовать, если (используя наш пример) вы хотите упорядочить по некоторому атрибуту Department. В противном случае (действителен по крайней мере для PG) вы можете получитьERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
в этой ссылке, которую я упоминал ранее в комментарии, прочитайте эту часть:
этот «JOIN FETCH» будет иметь эффект, если у вас есть свойство (fetch = FetchType.LAZY) для коллекции внутри сущности (пример ниже).
И это только эффект метода «когда должен произойти запрос». И вы должны также знать это :
когда выбирается ассоциация -> ваш тип "FETCH"
как это получается -> Присоединиться / выбрать / выбрать / пакет
В вашем случае, FETCH будет иметь эффект, только если у вас есть отдел как набор внутри Employee, что-то вроде этого в сущности:
когда вы используете
вы получите
emp
иemp.dep
. когда вы не использовали fetch, вы все равно можете получить,emp.dep
но hibernate обработает другой выбор в базе данных, чтобы получить этот набор отделов.так что это просто вопрос настройки производительности, о том, хотите ли вы получить весь результат (нужен он вам или нет) в одном запросе (активное получение) или вы хотите запросить его позже, когда вам это нужно (отложенное получение).
Используйте активную выборку, когда вам нужно получить небольшие данные одним выбором (один большой запрос). Или используйте ленивую выборку, чтобы запросить то, что вам нужно позже (много меньшего запроса).
использовать fetch, когда:
нет большой ненужной коллекции / набора внутри объекта, который вы собираетесь получить
связь между сервером приложений и сервером базы данных слишком велика и требует длительного времени
вам может понадобиться , что сбор последнего , когда у вас нет доступа к нему ( за пределы от транзакционного метода / класса)
источник
List
вместоSet
?FETCH
ключевого слова в выражении JPQL свойство, к которому вы стремитесь получить?ПРИСОЕДИНИТЬСЯ
Когда используешь
JOIN
отношении ассоциаций сущностей JPA будет генерировать JOIN между родительской сущностью и таблицами дочерних сущностей в сгенерированном операторе SQL.Итак, на вашем примере при выполнении этого запроса JPQL:
Hibernate собирается сгенерировать следующий оператор SQL:
ПРИСОЕДИНИТЬСЯ К FETCH
Таким образом, по сравнению с
JOIN
,JOIN FETCH
позволяет проецировать столбцы соединяющей таблицы вSELECT
предложении сгенерированного оператора SQL.Итак, в вашем примере при выполнении этого запроса JPQL:
Hibernate собирается сгенерировать следующий оператор SQL:
Кроме того,
JOIN FETCH
это отличный способ решения проблемыLazyInitializationException
при использовании Hibernate, поскольку вы можете инициализировать ассоциации сущностей, используяFetchType.LAZY
стратегию выборки вместе с основной сущностью, которую вы выбираете.источник
Если у вас установлено
@oneToOne
сопоставлениеFetchType.LAZY
и вы используете второй запрос (поскольку вам нужно, чтобы объекты Department загружались как часть объектов Employee), то, что будет делать Hibernate, будет выдавать запросы на выборку объектов Department для каждого отдельного объекта Employee, который он выбирает из БД.Позже в коде вы можете получить доступ к объектам Department через однозначную ассоциацию Employee и Department, и Hibernate не будет выдавать никаких запросов для получения объекта Department для данного Employee.
Помните, что Hibernate по-прежнему выдает запросы, равные количеству выбранных сотрудников. Hibernate выдаст одинаковое количество запросов в обоих вышеуказанных запросах, если вы хотите получить доступ к объектам Department всех объектов Employee
источник
Дерик: Я не уверен в том, что вы говорите, когда вы не используете fetch, результат будет иметь тип:
List<Object[ ]>
это означает список таблиц Object, а не список Employee.Когда вы используете fetch, есть только один выбор, и в результате получается список Employee,
List<Employee>
содержащий список отделов. Он отменяет ленивую декларацию объекта.источник
fetch
, ваш запрос будет возвращать только сотрудников. Если отделы, даже в этом случае, продолжают возвращаться, это потому, что ваше сопоставление между Employee и Department (a @OneToMany) установлено с помощью FetchType.EAGER. В этом случае любой HQL-fetch
запрос (с или без)FROM Employee
принесет все отделы.@OneToMany(fetch = FetchType.EAGER
). Если это не так, Департаменты не будут возвращены.select
было сделано в HQL. ПопробуйSELECT emp FROM Employee emp JOIN FETCH emp.department dep
. JPA / Hibernate имеют такое поведение возвращающиеList
изObject[]
когда вы ommit наSELECT
части.