Benvenuti alla Guida al Tutorial sull’Esempio della Cache di Primo Livello di Hibernate. Di recente abbiamo esaminato l’architettura di Hibernate, il mapping di Hibernate e come utilizzare l’HQL per eseguire query SQL in modo orientato agli oggetti. Oggi esamineremo uno degli aspetti importanti di Hibernate – la Cache di Hibernate.
Cache di Hibernate
La Cache di Hibernate può essere molto utile per ottenere prestazioni rapide dell’applicazione se utilizzata correttamente. L’idea alla base della cache è ridurre il numero di query al database, riducendo così il tempo di throughput dell’applicazione. Hibernate include diversi tipi di cache:
- Cache del Primo Livello: La cache del primo livello di Hibernate è associata all’oggetto Session. La cache del primo livello di Hibernate è abilitata per impostazione predefinita e non c’è modo di disabilitarla. Tuttavia, Hibernate fornisce metodi attraverso i quali possiamo eliminare gli oggetti selezionati dalla cache o svuotare completamente la cache. Qualsiasi oggetto memorizzato nella sessione non sarà visibile ad altre sessioni e quando la sessione viene chiusa, tutti gli oggetti memorizzati nella cache saranno persi.
- Cache del Secondo Livello: La cache del secondo livello di Hibernate è disabilitata per impostazione predefinita ma possiamo abilitarla tramite configurazione. Attualmente EHCache e Infinispan forniscono implementazioni per la cache del secondo livello di Hibernate e possiamo utilizzarle. Approfondiremo questo argomento nel prossimo tutorial sulla memorizzazione nella cache di Hibernate.
- Cache delle Query: Hibernate può anche memorizzare nella cache il set di risultati di una query. La cache delle query di Hibernate non memorizza lo stato delle entità effettive nella cache; memorizza solo valori identificativi e risultati di tipo valore. Quindi dovrebbe sempre essere utilizzata insieme alla cache del secondo livello.
Esempio di Caching di Hibernate – Cache del Primo Livello
Per il mio esempio di programma sul cache di primo livello di Hibernate, sto utilizzando la stessa configurazione come in Esempio HQL, puoi controllarlo e configurare le tabelle e popolarle con dati di esempio. Iniziamo prima a esaminare il programma, il suo output e poi affronteremo alcuni dei punti importanti relativi al Cache di Primo Livello di Hibernate. HibernateCacheExample.java
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateCacheExample {
public static void main(String[] args) throws InterruptedException {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
//Ottieni dipendente con id=1
Employee emp = (Employee) session.load(Employee.class, new Long(1));
printData(emp,1);
//Aspetta un po' per cambiare i dati nel backend
Thread.sleep(10000);
//Recupera gli stessi dati di nuovo, controlla i log che nessuna query è stata eseguita
Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
printData(emp1,2);
//Crea una nuova sessione
Session newSession = sessionFactory.openSession();
//Ottieni dipendente con id=1, notice the logs for query
Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1));
printData(emp2,3);
//INIZIO: esempio di evict per rimuovere un oggetto specifico dalla cache di primo livello di Hibernate
//Ottieni dipendente con id=2, la prima volta quindi query nei log
Employee emp3 = (Employee) session.load(Employee.class, new Long(2));
printData(emp3,4);
//evict dell'oggetto dipendente con id=1
session.evict(emp);
System.out.println("Session Contains Employee with id=1?"+session.contains(emp));
//poiché l'oggetto è rimosso dalla cache di primo livello, vedrai la query nei log
Employee emp4 = (Employee) session.load(Employee.class, new Long(1));
printData(emp4,5);
//questo oggetto è ancora presente, quindi non vedrai la query nei log
Employee emp5 = (Employee) session.load(Employee.class, new Long(2));
printData(emp5,6);
//FINE: esempio di evict
//INIZIO: esempio di clear per rimuovere tutto dalla cache di primo livello
session.clear();
Employee emp6 = (Employee) session.load(Employee.class, new Long(1));
printData(emp6,7);
Employee emp7 = (Employee) session.load(Employee.class, new Long(2));
printData(emp7,8);
System.out.println("Session Contains Employee with id=2?"+session.contains(emp7));
tx.commit();
sessionFactory.close();
}
private static void printData(Employee emp, int count) {
System.out.println(count+":: Name="+emp.getName()+", Zipcode="+emp.getAddress().getZipcode());
}
}
Quando eseguiamo l’esempio sopra, l’output contiene molte informazioni correlate a Hibernate. Ma siamo principalmente interessati all’output specifico del nostro codice e alle query eseguite da Hibernate per caricare i dati. Lo snippet dell’output appare come segue.
Hibernate Configuration loaded
Hibernate serviceRegistry created
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
1:: Name=Pankaj, Zipcode=95129
2:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
3:: Name=PankajK, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
4:: Name=David, Zipcode=95051
Session Contains Employee with id=1?false
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
5:: Name=Pankaj, Zipcode=95129
6:: Name=David, Zipcode=95051
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
7:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
8:: Name=David, Zipcode=95051
Session Contains Employee with id=2?true
Principali punti importanti sulla Cache del Primo Livello in Hibernate
I punti importanti sulla cache del primo livello in Hibernate che possono essere derivati dal programma sopra sono:
- La cache del primo livello di Hibernate è abilitata per impostazione predefinita, non sono necessarie configurazioni per questo.
- La cache del primo livello di Hibernate è specifica per la sessione, ecco perché quando otteniamo gli stessi dati nella stessa sessione non viene eseguita alcuna query, mentre in altre sessioni viene eseguita una query per caricare i dati.
- La cache del primo livello di Hibernate può contenere valori precedenti, come si può vedere dal programma sopra che ho messo in pausa per 10 secondi e in quel tempo ho aggiornato il valore (da Pankaj a PankajK) nel database ma non è stato riflesso nella stessa sessione. Ma in un’altra sessione abbiamo ottenuto il valore aggiornato.
- Possiamo utilizzare il metodo
evict()
della sessione per rimuovere un singolo oggetto dalla cache del primo livello di Hibernate. - Possiamo utilizzare il metodo
clear()
della sessione per svuotare la cache, cioè eliminare tutti gli oggetti dalla cache. - Possiamo utilizzare il metodo
contains()
della sessione per verificare se un oggetto è presente nella cache di Hibernate o meno, se l’oggetto viene trovato nella cache, restituisce true, altrimenti restituisce false. - Dato che Hibernate memorizza tutti gli oggetti nella cache del primo livello della sessione, durante l’esecuzione di query di massa o aggiornamenti batch è necessario svuotare la cache a intervalli regolari per evitare problemi di memoria.
Ecco tutto per l’esempio di caching di hibernate e di cache di primo livello, nei prossimi articoli esamineremo l’implementazione della Cache di secondo livello di Hibernate – EHCache.
Source:
https://www.digitalocean.com/community/tutorials/hibernate-caching-first-level-cache