Search code examples
javahibernateentityquery-performanceidentifier

Loading multiple entities by id efficiently in Hibernate


So, I'm getting a number of instances of a particular entity by id:

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

This generates a SQL query for each id, so it occurred to me that I should do this in one, but I couldn't find a way to get multiple entities in one call except by running a query. So I wrote a query

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

But, if I enable 2nd level caching doesn't that mean that my old method would be able to return the objects from the 2nd level cache (if they had been requested before) but my query would always go to the database.

What the correct way to do this?


Solution

  • What you're asking to do here is for Hibernate to do special case handling for your Criteria, which is kind of a lot to ask.

    You'll have to do it yourself, but it's not hard. Using SessionFactory.getCache(), you can get a reference to the actual storage for cached objects. Do something like the following:

    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);
    

    Then the Songs from the cache get retrieved from there, and the ones that are not get pulled with a single select.