Что именно контролирует стратегия извлечения JPA? Я не вижу разницы между нетерпеливым и ленивым. В обоих случаях JPA / Hibernate не присоединяется автоматически к отношениям «многие к одному».
Пример: у человека один адрес. Адрес может принадлежать многим людям. Аннотированные классы сущностей JPA выглядят так:
@Entity
public class Person {
@Id
public Integer id;
public String name;
@ManyToOne(fetch=FetchType.LAZY or EAGER)
public Address address;
}
@Entity
public class Address {
@Id
public Integer id;
public String name;
}
Если я использую запрос JPA:
select p from Person p where ...
JPA / Hibernate генерирует один запрос SQL для выбора из таблицы Person, а затем отдельный запрос адреса для каждого человека:
select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3
Это очень плохо для больших наборов результатов. Если есть 1000 человек, он генерирует 1001 запрос (1 от Person и 1000 от Address). Я знаю это, потому что смотрю журнал запросов MySQL. Насколько я понимаю, установка типа выборки адреса на нетерпеливое приведет к тому, что JPA / Hibernate автоматически запросит соединение. Однако, независимо от типа выборки, он по-прежнему генерирует отдельные запросы для отношений.
Только когда я явно говорю ему присоединиться, он действительно присоединяется:
select p, a from Person p left join p.address a where ...
Я что-то упустил? Теперь мне нужно передать код для каждого запроса, чтобы он оставался соединенным с отношениями «многие к одному». Я использую реализацию JPA Hibernate с MySQL.
Изменить: похоже (см. Часто задаваемые вопросы о Hibernate здесь и здесь ), что FetchType
не влияет на запросы JPA. Так что в моем случае я прямо сказал ему присоединиться.
Ответы:
JPA не предоставляет никаких спецификаций по отображению аннотаций для выбора стратегии выборки. Как правило, связанные сущности можно получить любым из способов, указанных ниже.
Так
SELECT
иJOIN
две крайности иSUBSELECT
падает между ними. Можно выбрать подходящую стратегию на основе модели предметной области.По умолчанию
SELECT
используется как JPA / EclipseLink, так и Hibernate. Это можно изменить, используя:в Hibernate. Это также позволяет
SELECT
явно установить режим,@Fetch(FetchMode.SELECT)
который можно настроить, используя размер пакета, например@BatchSize(size=10)
.Соответствующие аннотации в EclipseLink:
источник
"mxc" правильно.
fetchType
просто указывает, когда должно быть разрешено отношение.Чтобы оптимизировать нетерпеливую загрузку с помощью внешнего соединения, вам нужно добавить
на свое поле. Это специальная аннотация для гибернации.
источник
Атрибут fetchType определяет, извлекается ли аннотированное поле сразу после выборки основного объекта. Это не обязательно диктует, как создается оператор выборки, фактическая реализация sql зависит от поставщика, который вы используете toplink / hibernate и т. Д.
Если вы установите
fetchType=EAGER
Это означает, что аннотированное поле заполняется своими значениями одновременно с другими полями в сущности. Поэтому, если вы открываете entitymanager, извлекаете свои объекты person, а затем закрываете entitymanager, последующее выполнение person.address не приведет к возникновению исключения ленивой загрузки.Если вы установите
fetchType=LAZY
поле заполняется только при доступе к нему. Если к этому моменту вы закрыли entitymanager, будет сгенерировано исключение ленивой загрузки, если вы введете person.address. Чтобы загрузить поле, вам нужно вернуть объект в контекст entitymangers с помощью em.merge (), затем выполнить доступ к полю и затем закрыть entitymanager.При создании класса клиентов с коллекцией заказов клиентов может потребоваться отложенная загрузка. Если вы извлекали каждый заказ для клиента, когда хотели получить список клиентов, это может быть дорогостоящей операцией с базой данных, когда вы ищете только имя клиента и контактные данные. Лучше оставить доступ к БД на потом.
По второй части вопроса - как заставить спящий режим генерировать оптимизированный SQL?
Hibernate должен позволить вам давать подсказки относительно того, как построить наиболее эффективный запрос, но я подозреваю, что что-то не так с построением вашей таблицы. Установлены ли отношения в таблицах? Hibernate, возможно, решил, что простой запрос будет быстрее, чем соединение, особенно если отсутствуют индексы и т. Д.
источник
Попробуйте:
У меня это работает аналогично JPA2 / EclipseLink, но похоже, что эта функция присутствует и в JPA1 :
источник
Если вы используете EclipseLink вместо Hibernate, вы можете оптимизировать свои запросы с помощью «подсказок». См. Эту статью в Eclipse Wiki: EclipseLink / Примеры / JPA / QueryOptimization .
Есть глава о «Совместном чтении».
источник
чтобы присоединиться, вы можете делать несколько вещей (используя eclipselink)
в jpql вы можете выполнить выборку с левым соединением
в именованном запросе вы можете указать подсказку запроса
в TypedQuery вы можете сказать что-то вроде
query.setHint("eclipselink.join-fetch", "e.projects.milestones");
есть также подсказка по пакетной выборке
query.setHint("eclipselink.batch", "e.address");
видеть
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html
источник
У меня была именно эта проблема, за исключением того, что класс Person имел встроенный ключевой класс. Мое собственное решение заключалось в том, чтобы присоединиться к ним в запросе И удалить
@Fetch(FetchMode.JOIN)
Мой встроенный класс идентификатора:
источник
Мне приходят в голову две вещи.
Во-первых, вы уверены, что имеете в виду ManyToOne для адреса? Это означает, что несколько человек будут иметь один и тот же адрес. Если он отредактирован для одного из них, он будет отредактирован для всех. Это ваше намерение? 99% времени адреса являются «частными» (в том смысле, что они принадлежат только одному человеку).
Во-вторых, есть ли у вас какие-либо другие активные отношения с сущностью Person? Если я правильно помню, Hibernate может обрабатывать только одно стремительное отношение к объекту, но это, возможно, устаревшая информация.
Я говорю это, потому что ваше понимание того, как это должно работать, по существу правильное с того места, где я сижу.
источник