#java #hibernate #jpa #one-to-many #eager-loading
#java #спящий режим #jpa #один ко многим #нетерпеливая загрузка
Вопрос:
У меня есть следующая модель:
public class BaseModel {
List<DataA> lazyCollectionA;
List<DataB> lazyCollectionB;
}
public class DataA {
OtherEntity otherEntity;
}
public class OtherEntity {
List<DataC> lazyCollectionC;
}
Когда я посещаю определенную страницу, мне нужно использовать все эти данные. Это создает проблему выбора производительности n 1.
Я уже частично решил проблему, охотно извлекая коллекции с помощью:
List<BaseModel> result = entityManager.createQuery(
"select m from BaseModel m "
"left join fetch m.lazyCollectionA "
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
result = entityManager.createQuery(
"select m from BaseModel m "
"left join fetch m.lazyCollectionB "
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
Обратите внимание, что мне пришлось выполнить 2 запроса вместо только 1, потому что в противном случае я бы получил MultipleBagFetchException
.
Однако у меня возникают проблемы с загрузкой. lazyCollectionA.otherEntity.lazyCollectionC
Я попробовал несколько вариантов запроса, чтобы попытаться быстро получить результаты, но при otherEntity.lazyCollectionC
доступе проблема выбора n 1 продолжает всплывать.
Я думаю, что это должно сработать, но, к сожалению, это не так:
entityManager.createQuery(
"select a from BaseModel m "
"left join m.lazyCollectionA a "
"left join fetch a.otherEntity o "
"left join fetch o.lazyCollectionC "
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
У вас есть какие-либо идеи, почему это не работает?
Кроме того, я не совсем понимаю, как загружаются lazyCollectionA
и работают мои первые 2 запроса lazyCollectionB
. Я имею в виду, поскольку они загружаются в разное время, я бы ожидал, что только последний запрос будет иметь загруженные экземпляры. Это потому, что hibernate кэширует результаты, и поэтому ему не нужно снова запрашивать базу данных?
Спасибо за любую помощь, которую вы можете предоставить!
Ответ №1:
Я предполагаю, что все соединения между вашими моделями являются @OneToMany. В этом случае вы могли бы попробовать что-то вроде этого:
@Autowired
private EntityManager em;
@Transactional
public List<BaseModel> getAllByThreeQueries() {
List<Long> ids = Arrays.asList(1L);
List<BaseModel> first = em.createQuery(
"select distinct m from BaseModel m "
"left join fetch m.lazyCollectionB "
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
List<BaseModel> second = em.createQuery(
"select distinct m from BaseModel m "
"left join fetch m.lazyCollectionA a "
"left join fetch a.otherEntity o "
"where m in (:models) ", BaseModel.class)
.setParameter("models", first)
.getResultList();
em.createQuery("select distinct a from BaseModel m "
"left join m.lazyCollectionA a "
"left join fetch a.otherEntity o "
"left join fetch o.lazyCollectionC "
"where m in (:models) ", DataA.class)
.setParameter("models", second)
.getResultList();
return second;
}
У вас есть какие-либо идеи, почему это не работает?
entityManager.createQuery(
"select a from BaseModel m "
"left join m.lazyCollectionA a "
"left join fetch a.otherEntity o "
"left join fetch o.lazyCollectionC "
"where m.id in (:ids) ", BaseModel.class)
.setParameter("ids", ids)
.getResultList();
Потому что в этом случае вы получаете исключение MultipleBagFetchException. Вам нужно выполнить еще один запрос.
Комментарии:
1. Спасибо за ваш вклад! К сожалению, у меня это не сработало. Запросы select n 1 для выборки
lazyCollectionC
все еще выполняются. Я заметил, что эти запросы используютWHERE dataC.otherEntity_id = ?
. Я попытался воспроизвести это предложение where, но n 1 запросов все равно появляются.2. Также я попытался получить доступ к ссылке на полный код, которую вы опубликовали, но она выдает ошибку 404 :/
3. Извините, я забыл открыть репозиторий. Теперь я это сделал. Вы можете просмотреть ее.
4. Не могли бы вы предоставить больше информации о своей среде? Например, метод полного запроса, отношения между моделями, аннотации классов или методов или полей?