Эффективная загрузка нескольких сущностей по id в HIbernate 4 - PullRequest
13 голосов
/ 23 февраля 2012

Итак, я получаю количество экземпляров определенной сущности по идентификатору

for(Integer songId:songGroup.getSongIds())
{
   session = HibernateUtil.getSession();
   Song song = (Song) session.get(Song.class,id);
   processSong(song);
}

это генерирует sql-запрос для каждого идентификатора, поэтому мне пришло в голову, что я должен сделать это за один, но я не смог найти способ получить несколько сущностей за один вызов, кроме как путем выполнения запроса. Поэтому я написал запрос

return (List) session.createCriteria(Song.class)
       .add(Restrictions.in("id",ids)).list();

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

Какой правильный способ сделать это?

Ответы [ 4 ]

9 голосов
/ 27 июня 2013

То, что вы просите сделать, - это чтобы Hibernate выполнял обработку особых случаев для ваших Критериев, что довольно много.

Тебе придется сделать это самому, но это не сложно. Используя SessionFactory.getCache(), вы можете получить ссылку на фактическое хранилище для кэшированных объектов. Сделайте что-то вроде следующего:

for (Long id : allRequiredIds) {
  if (!sessionFactory.getCache().containsEntity(Song.class, id)) {
    idsToQueryDatabaseFor.add(id)
  } else {
    songs.add(session.get(Song.class, id));
  }
}

List<Song> fetchedSongs = session.createCriteria(Song.class).add(Restrictions.in("id",idsToQueryDatabaseFor).list();
songs.addAll(fetchedSongs);

Затем оттуда извлекаются песни из кеша, а те, которые не извлекаются одним select.

1 голос
/ 20 апреля 2015

Если вы знаете, что идентификаторы существуют, вы можете использовать load (..) для создания прокси без фактического обращения к БД:

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

List<Song> list = new ArrayList<>(ids.size());
for (Integer id : ids)
  list.add(session.load(Song.class, id, LockOptions.NONE));

Как только вы получите доступ к неидентификатору доступа, Hibernate проверит кеши и откат к БД, если необходимо, используя пакетную выборку, если настроено.

Если идентификатор не существует, исключение ObjectNotFoundException произойдет после загрузки объекта. Это может быть где-то в вашем коде, где вы не ожидаете исключения - в конце вы используете простой метод доступа. Поэтому будьте на 100% уверены, что идентификатор существует, или, по крайней мере, форсируйте исключение ObjectNotFoundException раньше, чем вы ожидаете, например, сразу после заполнения списка.

0 голосов
/ 05 сентября 2014

Еще одна вещь, которую вы могли бы сделать, это отсортировать список идентификаторов и определить подпоследовательности последовательных идентификаторов, а затем запросить каждую из этих подпоследовательностей в одном запросе. Например, учитывая List<Long> ids, сделайте следующее (при условии, что у вас есть класс Pair в Java):

List<Pair> pairs=new LinkedList<Pair>();
List<Object> results=new LinkedList<Object>();
Collections.sort(ids);
Iterator<Long> it=ids.iterator();

Long previous=-1L;
Long sequence_start=-1L;
while (it.hasNext()){
    Long next=it.next();

    if (next>previous+1) {
        pairs.add(new Pair(sequence_start, previous));
        sequence_start=next;
    }
    previous=next;
}
pairs.add(new Pair(sequence_start, previous));

for (Pair pair : pairs){
    Query query=session.createQuery("from Person p where p.id>=:start_id and p.id<=:end_id");
    query.setLong("start_id", pair.getStart());
    query.setLong("end_id", pair.getEnd());

    results.addAll((List<Object>)query.list());

}
0 голосов
/ 24 июня 2013

Существует разница между кэшем 2-го уровня гибернации и кэшем запросов гибернации. Следующая ссылка объясняет это очень хорошо: http://www.javalobby.org/java/forums/t48846.html

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

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