Ibernazione - Caching

La memorizzazione nella cache è un meccanismo per migliorare le prestazioni di un sistema. È una memoria buffer che si trova tra l'applicazione e il database. La memoria cache memorizza gli elementi di dati utilizzati di recente per ridurre il più possibile il numero di accessi al database.

La memorizzazione nella cache è importante anche per Hibernate. Utilizza uno schema di memorizzazione nella cache multilivello come spiegato di seguito:

Cache di primo livello

La cache di primo livello è la cache di sessione ed è una cache obbligatoria attraverso la quale devono passare tutte le richieste. L'oggetto Session mantiene un oggetto sotto il proprio potere prima di inviarlo al database.

Se si emettono più aggiornamenti a un oggetto, Hibernate tenta di ritardare l'esecuzione dell'aggiornamento il più a lungo possibile per ridurre il numero di istruzioni SQL di aggiornamento emesse. Se si chiude la sessione, tutti gli oggetti memorizzati nella cache vengono persi e vengono mantenuti o aggiornati nel database.

Cache di secondo livello

La cache di secondo livello è una cache opzionale e la cache di primo livello verrà sempre consultata prima di tentare di individuare un oggetto nella cache di secondo livello. La cache di secondo livello può essere configurata per classe e per raccolta ed è principalmente responsabile della memorizzazione nella cache degli oggetti tra le sessioni.

Qualsiasi cache di terze parti può essere utilizzata con Hibernate. Unorg.hibernate.cache.CacheProvider viene fornita l'interfaccia, che deve essere implementata per fornire a Hibernate un handle per l'implementazione della cache.

Cache a livello di query

Hibernate implementa anche una cache per i set di risultati delle query che si integra strettamente con la cache di secondo livello.

Si tratta di una funzionalità facoltativa e richiede due aree cache fisiche aggiuntive che contengono i risultati delle query memorizzate nella cache e i timestamp dell'ultimo aggiornamento di una tabella. Ciò è utile solo per le query eseguite di frequente con gli stessi parametri.

La cache di secondo livello

Hibernate utilizza la cache di primo livello per impostazione predefinita e non devi fare nulla per utilizzare la cache di primo livello. Andiamo direttamente alla cache di secondo livello opzionale. Non tutte le classi traggono vantaggio dalla memorizzazione nella cache, quindi è importante essere in grado di disabilitare la cache di secondo livello.

La cache di secondo livello di Hibernate viene configurata in due passaggi. Innanzitutto, devi decidere quale strategia di concorrenza utilizzare. Successivamente, configurare la scadenza della cache e gli attributi della cache fisica utilizzando il provider della cache.

Strategie di concorrenza

Una strategia di concorrenza è un mediatore, responsabile dell'archiviazione di elementi di dati nella cache e del loro recupero dalla cache. Se si intende abilitare una cache di secondo livello, sarà necessario decidere, per ciascuna classe e raccolta persistente, quale strategia di concorrenza della cache utilizzare.

  • Transactional - Utilizzare questa strategia per i dati per lo più di lettura in cui è fondamentale prevenire dati obsoleti nelle transazioni simultanee, nel raro caso di un aggiornamento.

  • Read-write - Usa ancora questa strategia per i dati per lo più in lettura, dove è fondamentale prevenire dati obsoleti nelle transazioni simultanee, nel raro caso di un aggiornamento.

  • Nonstrict-read-write- Questa strategia non garantisce la coerenza tra la cache e il database. Utilizzare questa strategia se i dati non cambiano quasi mai e una piccola probabilità di dati obsoleti non è di fondamentale importanza.

  • Read-only- Una strategia di concorrenza adatta ai dati, che non cambia mai. Usalo solo per i dati di riferimento.

Se utilizzeremo la memorizzazione nella cache di secondo livello per il nostro file Employee class, aggiungiamo l'elemento di mappatura richiesto per dire a Hibernate di memorizzare nella cache le istanze Employee utilizzando la strategia di lettura-scrittura.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <cache usage = "read-write"/>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

L'attributo usage = "read-write" indica a Hibernate di utilizzare una strategia di concorrenza di lettura-scrittura per la cache definita.

Provider di cache

Il passaggio successivo dopo aver considerato le strategie di concorrenza, utilizzerai le classi candidate alla cache per scegliere un provider di cache. Hibernate ti obbliga a scegliere un unico provider di cache per l'intera applicazione.

Sr.No. Nome e descrizione cache
1

EHCache

Può memorizzare nella cache o su disco e la cache in cluster e supporta la cache dei risultati della query Hibernate opzionale.

2

OSCache

Supporta la memorizzazione nella cache su memoria e disco in una singola JVM con un ricco set di criteri di scadenza e supporto per la cache delle query.

3

warmCache

Una cache del cluster basata su JGroups. Utilizza l'invalidazione in cluster, ma non supporta la cache delle query di Hibernate.

4

JBoss Cache

Una cache cluster replicata completamente transazionale anche basata sulla libreria multicast JGroups. Supporta la replica o l'invalidazione, la comunicazione sincrona o asincrona e il blocco ottimistico e pessimistico. La cache delle query di Hibernate è supportata.

Ogni provider di cache non è compatibile con tutte le strategie di concorrenza. La seguente matrice di compatibilità ti aiuterà a scegliere una combinazione appropriata.

Strategia / fornitore Sola lettura Nonstrictread-write Leggere scrivere Transazionale
EHCache X X X  
OSCache X X X  
SwarmCache X X    
JBoss Cache X     X

Specifichi un provider di cache nel file di configurazione hibernate.cfg.xml. Scegliamo EHCache come nostro provider di cache di secondo livello -

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory>
   
      <property name = "hibernate.dialect">
         org.hibernate.dialect.MySQLDialect
      </property>
   
      <property name = "hibernate.connection.driver_class">
         com.mysql.jdbc.Driver
      </property>
   
      <!-- Assume students is the database name -->
   
      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>
   
      <property name = "hibernate.connection.username">
         root
      </property>
   
      <property name = "hibernate.connection.password">
         root123
      </property>
   
      <property name = "hibernate.cache.provider_class">
         org.hibernate.cache.EhCacheProvider
      </property>
   
      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>
   
   </session-factory>
</hibernate-configuration>

Ora è necessario specificare le proprietà delle regioni della cache. EHCache ha il proprio file di configurazione,ehcache.xml, che dovrebbe trovarsi nel CLASSPATH dell'applicazione. Una configurazione della cache in ehcache.xml per la classe Employee potrebbe essere simile a questa:

<diskStore path="java.io.tmpdir"/>

<defaultCache
maxElementsInMemory = "1000"
eternal = "false"
timeToIdleSeconds = "120"
timeToLiveSeconds = "120"
overflowToDisk = "true"
/>

<cache name = "Employee"
maxElementsInMemory = "500"
eternal = "true"
timeToIdleSeconds = "0"
timeToLiveSeconds = "0"
overflowToDisk = "false"
/>

Ecco fatto, ora abbiamo la cache di secondo livello abilitata per la classe Employee e Hibernate, ora colpisce la cache di secondo livello ogni volta che navighi su un dipendente o quando carichi un dipendente per identificatore.

È necessario analizzare tutte le classi e scegliere la strategia di memorizzazione nella cache appropriata per ciascuna delle classi. A volte, la memorizzazione nella cache di secondo livello può ridurre le prestazioni dell'applicazione. Pertanto, si consiglia di eseguire prima il benchmark della tua applicazione, senza abilitare la memorizzazione nella cache e successivamente abilitare la memorizzazione nella cache adatta e controllare le prestazioni. Se la memorizzazione nella cache non migliora le prestazioni del sistema, non ha senso abilitare alcun tipo di memorizzazione nella cache.

La cache a livello di query

Per utilizzare la cache delle query, è necessario prima attivarla utilizzando il hibernate.cache.use_query_cache="true"proprietà nel file di configurazione. Impostando questa proprietà su true, fai in modo che Hibernate crei le cache necessarie in memoria per contenere le serie di query e identificatori.

Successivamente, per utilizzare la cache delle query, si utilizza il metodo setCacheable (Boolean) della classe Query. Ad esempio:

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
List users = query.list();
SessionFactory.closeSession();

Hibernate supporta anche il supporto della cache a grana molto fine attraverso il concetto di una regione della cache. Una regione della cache fa parte della cache a cui è stato assegnato un nome.

Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();

Questo codice utilizza il metodo per dire a Hibernate di memorizzare e cercare la query nell'area dei dipendenti della cache.