Memorizzazione nella cache di Hibernate – Cache di primo livello

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:

  1. 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.
  2. 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.
  3. 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:

  1. La cache del primo livello di Hibernate è abilitata per impostazione predefinita, non sono necessarie configurazioni per questo.
  2. 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.
  3. 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.
  4. Possiamo utilizzare il metodo evict() della sessione per rimuovere un singolo oggetto dalla cache del primo livello di Hibernate.
  5. Possiamo utilizzare il metodo clear() della sessione per svuotare la cache, cioè eliminare tutti gli oggetti dalla cache.
  6. 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.
  7. 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