2012-02-23 7 views
13

Così Im ottenere un numero di istanze di una particolare entità da idCaricamento più entità di id in modo efficiente in Hibernate 4

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

questo genera una query SQL per ogni ID, quindi occurred a me che devo fare questo in uno, ma non sono riuscito a trovare un modo per ottenere più entità in una chiamata, tranne eseguendo una query. Così ho scritto una query

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

ma se abilito 2 ° livello di caching non vuol dire che il mio vecchio metodo sarebbe in grado di restituire gli oggetti dalla cache di 2 ° livello (se fossero stati richiesti in precedenza), ma il mio la query andrebbe sempre nel database.

Qual è il modo corretto per farlo?

+0

Hai mai trovato un modo per farlo? – FGreg

risposta

8

Quello che stai chiedendo di fare qui è che Hibernate si occuperà di gestire casi speciali per i tuoi Criteri, il che è un po 'troppo da chiedere.

Dovrai farlo da solo, ma non è difficile. Utilizzando SessionFactory.getCache(), è possibile ottenere un riferimento alla memoria effettiva per gli oggetti memorizzati nella cache. Fare qualcosa di simile al seguente:

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

Poi i brani dalla cache vengono recuperati da lì, e quelli che non sono ottenere tirato con un unico select.

+0

grazie che ha un senso –

0

C'è una differenza tra la cache di secondo livello di ibernazione e la cache di query di ibernazione. Il seguente link lo spiega molto bene: http://www.javalobby.org/java/forums/t48846.html

In poche parole, Se si utilizza la stessa query più volte con gli stessi parametri, allora si può ridurre del database colpisce utilizzando una combinazione di entrambi.

0

Un'altra cosa che si potrebbe fare è ordinare l'elenco di id e identificare sottosequenze di ID consecutivi e quindi interrogare ciascuna di tali sottosequenze in una singola query. Ad esempio, dato List<Long> ids, procedere come segue (supponendo che si dispone di una classe alla pari lavoro in 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

Se si sa che gli ID esiste, è possibile utilizzare load(..) per creare un proxy senza realmente colpire il DB:

restituire l'istanza persistente data classe entità con l'identificatore dato, ottenendo la modalità di blocco specificato, assumendo esiste l'istanza.

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

Una volta che si accede una funzione di accesso non-identificatore, Hibernate controllerà la cache e fallback a DB, se necessario, utilizzando batch recupero se configurato.

Se l'ID non esiste, verrà eseguita una ObjectNotFoundException una volta caricato l'oggetto. Questo potrebbe essere da qualche parte nel tuo codice in cui non ti aspetteresti davvero un'eccezione - stai utilizzando un semplice accessorio alla fine. Quindi, assicurati al 100% che l'ID esista o almeno forzare anticipatamente una ObjectNotFoundException dove ti aspetteresti, ad es. subito dopo aver compilato la lista.

Problemi correlati