2012-02-23 4 views
13

Alors Im obtenir un certain nombre d'instances d'une entité particulière par idChargement de plusieurs entités par identifiant efficacement dans HIBERNATE 4

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

cela génère une requête SQL pour chaque identifiant, il me ocurred que je devrais faire ceci dans un, mais je ne pourrais pas trouver un moyen d'obtenir plusieurs entités dans un appel excepté en exécutant une requête. J'ai donc écrit une requête

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

mais si j'activer la mise en cache de niveau 2 ne veut pas que cela signifie que mon ancienne méthode serait en mesure de restituer les objets à partir du cache de niveau 2 (si elles avaient été demandés avant) mais mon requête irait toujours à la base de données.

Quelle est la bonne façon de procéder?

+0

Avez-vous déjà trouvé un moyen de le faire? – FGreg

Répondre

8

Ce que vous demandez ici, c'est que Hibernate s'occupe de la gestion des dossiers pour vos critères, ce qui est une question à poser.

Vous devrez le faire vous-même, mais ce n'est pas difficile. En utilisant SessionFactory.getCache(), vous pouvez obtenir une référence au stockage réel pour les objets mis en cache. Faites quelque chose comme ce qui suit:

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

Ensuite, les morceaux du cache à partir de là se récupérer, et ceux qui ne sont pas ballotés avec un seul select.

+0

merci cela a du sens –

0

Il existe une différence entre le cache de second niveau d'hibernation pour hiberner le cache de requête. Le lien suivant explique très bien: http://www.javalobby.org/java/forums/t48846.html

En un mot, Si vous utilisez la même requête plusieurs fois avec les mêmes paramètres, vous pouvez réduire la base de données frappe en utilisant une combinaison des deux.

0

Une autre chose que vous pourriez faire est de trier la liste des identifiants, et identifier les sous-séquences d'identifiants consécutifs, puis interroger chacune de ces sous-séquences dans une seule requête. Par exemple, étant donné List<Long> ids, procédez comme suit (en supposant que vous avez une classe de pair en 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()); 

} 
1

Si vous savez que les ID existent, vous pouvez utiliser load(..) pour créer un proxy sans toucher réellement le DB:

Renvoie l'instance persistante de la classe d'entité donnée avec l'identificateur donné, obtenant le mode de verrouillage spécifié, en supposant que l'instance existe.

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

Une fois que vous accédez à un accesseur non identifiant, Hibernate vérifiera les caches et à DB si fallback nécessaire, en utilisant la fonction de récupération lot si elle est configurée.

Si l'ID n'existe pas, une exception ObjectNotFoundException se produit une fois l'objet chargé. Cela pourrait être quelque part dans votre code où vous n'attendriez pas vraiment une exception - vous utilisez un simple accesseur à la fin. Donc, soit être sûr à 100% que l'ID existe, soit au moins forcer une ObjectNotFoundException tôt où vous l'attendez, par ex. juste après le remplissage de la liste.

Questions connexes