venerdì 10 febbraio 2012

L'utilizzo della cache in Nhibernate

Una grande funzionalità che possiede Nhibernate è quella della possibilità di gestire e personalizzare l'utilizzo della cache.
Per differenziarsi dalla cache che nhibernate utlizza nativamente (cache di primo livello), quella, la cui gestione è delegata a noi utilizzatori, è chiamata cache di secondo livello.

Il suo utilizzo è davvero semplice.

Ammettiamo di avere una tabella di configurazione nel nostro database (t_configuration), e di avere la relativa classe mappata (ConfigurationEntry)

E' naturale che noi vorremmo cachare il contenuto di tale tabella, poichè probabilmente verrà modificata raramente e, allo stesso tempo,utilizzata di frequente.
Quello che è necesario fare è aggiungere al file di mapping della classe il seguente tag:

<cache 
    usage="read-write|nonstrict-read-write|read-only"                
    region="RegionName"                                              
/>

usage
read-only: nel caso i dati vengano sempre solo letti (è il nostro caso)
read-write: nel caso i dati possano essere sia letti che scritti (controllare che il provider di caching scelto abbia il supporto al locking)
nonstrict-read-write: nel caso i dati possano essere letti e raramente scritti. Dunque probabilmente è possibile trascurare casi di transazioni simultanee

region
RegionName: nome della regione di cache (di default il nome della classe)

Dunque nel nostro caso avremo un file di mapping simile al seguente:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping namespace="Test" assembly="Test" 
xmlns="urn:nhibernate-mapping-2.2">
<class name="ConfigurationEntry" table="t_configuration" schema="dbo">
       <cache usage="read-only"/>
       <id name="Key" access="property" column="Key">
         <generator class="assigned" />
       </id>
       <property name="Value" type="String" column="Value" length="50" />
</class>
</hibernate-mapping>
 
A questo punto se proviamo a eseguire per due volte consecutive la seguente funzione passandogli lo stesso parametro key

public string GetValueByKey(string key)
{ 
   return Session.Get<ConfigurationEntry>(key);
}

potremmo notare che solo la prima volta viene eseguito l'accesso al database, mentre la seconda volta il valore viene prelevato direttamente dalla cache.

Attenzione però che tale cache viene utilizzata solo per restituire le entità a partire dalla loro chiave. Nhibernate infatti ha messo in cache la coppia chiave-classe. Ma cosa accade quindi se io lancio per due volte consecutive la seguente funzione che mi restituisce tutti i record di configurazione?


public List<ConfigEntry> GetAllConfigurationEntries()
{
   return Session.CreateCriteria<ConfigurationEntry>()
.List<ConfigurationEntry>().ToList();
}

Ebbene l'accesso al database viene effettuato in entrambi i casi. Questo perchè Nhibernate non ha messo in cache la query ma solo le coppie chiave-classe.

Per tale motivo ci viene in aiuto la cosidetta Query Cache, che permette a Nhibernate di mettere in cache il risultato della query. La query cache viene attivata nel seguente modo:

public List<ConfigEntry> GetAllConfigurationEntries()
{
   return Session.CreateCriteria<ConfigurationEntry>().SetCacheable(true)
           .List<ConfigurationEntry>().ToList();
}


Ora eseguendo due volte la funzione, viene effettuato un solo accesso al database.
Attenzione che la query cache mette in cache solo le chiavi del risultato della query. E' necessario dunque abilitare anche la cache di secondo livello alla classe in questione, come abbiamo visto prima.


Nessun commento:

Posta un commento