Lingue per esperti di dominio, non solo per programmatori

In questo tutorial, exploreremo l’implementazione di un cache secondario di secondo livello in Hibernate utilizzando NCache.

Impareremo a configurare un’applicazione Java con Hibernate, poi configurare NCache come cache secondario. Infine, testeremo l’implementazione per vedere come il caching riduca il carico del database e migliora le prestazioni.

Basic

Prima di approfondire l’implementazione, perché non comprenderemo i fondamenti di Hibernate, NCache e del cache secondario di Hibernate.

Hibernate

Hibernate è un framework open source per la mappatura delle classi Java alle tabelle del database, noto come framework di mapping oggetto-relazione (ORM) per applicazioni Java. Simplifica lo sviluppo delle interazioni col database mappando oggetti Java the tabelle del database e viceversa.

Per migliorare le prestazioni, Hibernate fornisce due livelli di cache:

1. Cache di primo livello

Il cache di primo livello è associato alla sessione Hibernate ed è abilitato in modo predefinito. Memorizza gli oggetti recuperati durante una sessione, eliminando la necessità di accedere al database più di una volta per lo stesso oggetto.

Il cache di primo livello ha un scope limitato alla sessione e non è condiviso tra le sessioni.

Non è anche persistente e viene svuotato quando la sessione è chiusa o svuotata esplicitamente.

2. Cache secondario

La cache a livello secondario è condivisa tra le sessioni e può essere configurata per cacheggiare i dati a livello di applicazione. riduce il numero di accessi al database immagazzinando gli oggetti per un periodo più lungo.

La cache a livello secondario deve essere configurata esplicitamente e può essere implementata utilizzando diversi provider di cache come NCache, Ehcache, ecc.

NCache

NCache è una soluzione di cache distribuita per applicazioni .NET e Java. Fornisce un data store in memoria che può essere utilizzato per cacheare dati frequentemente accessi e migliorare le prestazioni dell’applicazione.

NCache supporta varie topologie di cache come ripetute, partitionate e cache client.

NCache può essere utilizzato come cache a livello secondario in Hibernate per memorizzare e recuperare gli oggetti dalla cache invece di effettuare richieste al database.

Impostazione del codice

Inizieremo creando un’applicazione Java e configurando Hibernate per interagire con il database.

Usareremo Maven per gestire le dipendenze e costruire il progetto. L’applicazione avrà una classe entità per definire i dati e una classe client per interagire con il database.

Prima, testeremo l’applicazione senza cache per vedere le interazioni col database. Poi, configurareremo NCache come cache a livello secondario in Hibernate per cacheare gli oggetti entità e ridurre gli accessi al database.

Dipendenze

Inizieremo aggiungendo le dipendenze necessarie per Hibernate e NCache nel file pom.xml:

<dependencies> <!-- Hibernate dependencies --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>6.6.1.Final</version> </dependency> <!-- NCache dependencies --> <dependency> <groupId>com.alachisoft.ncache</groupId> <artifactId>ncache-hibernate</artifactId> <version>5.3.3</version> </dependency> </dependencies>

Si prevede che le versioni indicate qui possano variare in base alle ultime release. Assicurarsi di utilizzare le versioni appropriate per il progetto.

Classe Entità

Poi, creiamo una classe entità per rappresentare i dati da cercare in cache. Definiamo una semplice classe Cliente con campi id e nome:

@Entity @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "CustomerRegion") public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // getters and setters }

La classe Cliente è annotata con @Entity e @Cacheable per definirla come un’entità cacheabile. Ha un campo id annotato con @Id e @GeneratedValue per generare automaticamente identificatori univoci.

Usiamo anche l’annotazione @Cache per specificare la strategia di caching e la regione per l’entità.

NONSTRICT_READ_WRITE informa Hibernate di aggiornare il cache quando i dati sono letti o scritti con eventuale coerenza.

L’attributo region specifica la regione cache dove i dati verranno memorizzati.

Configureremo NCache per utilizzare questa regione per memorizzare i dati in cache.

Configurazione di Hibernate

Dobbiamo configurare Hibernate per interagire con il database e abilitare il caching.

Creiamo un file hibernate.cfg.xml nella directory src/main/resources con la seguente configurazione:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:xe</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.dialect">org.hibernate.dialect.Oracle12cDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> </session-factory> </hibernate-configuration>

In questo file di configurazione, specificheremo dettagli di connessione al database, dialetto e impostazioni di cache. Usiamo Oracle come database e configuriamo Hibernate per aggiornare il schema automaticamente.

Classe Cliente

Creiamo una classe client per interagire con il database e testare il meccanismo di cache. Possiamo scrivere una classe main per salvare e recuperare oggetti Customer utilizzando Hibernate:

public class HibernateClient { public static void main(String[] args) { SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setName("John Doe"); session.save(customer); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); Customer retrievedCustomer = session.get(Customer.class, customer.getId()); System.out.println("Retrieved Customer: " + retrievedCustomer.getName()); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); retrievedCustomer = session.get(Customer.class, customer.getId()); System.out.println("Retrieved Customer: " + retrievedCustomer.getName()); transaction.commit(); session.close(); } }

In questa classe client, creiamo una SessionFactory utilizzando la configurazione di Hibernate e apriamo una sessione per interagire con il database. Saliamo un oggetto Customer nel database e lo recuperiamo utilizzando l’id.

Successivamente, chiamiamo il metodo retrieveCustomer due volte in due sessioni separate per vedere le interazioni del database senza il cache.

Osserviamo che il database viene contattato due volte per recuperare lo stesso oggetto:

Come vediamo, la query di Hibernate viene eseguita due volte.

Configurazione del Server NCache

Per utilizzare NCache come cache a livello secondario in Hibernate, abbiamo bisogno di impostare un server NCache e configurarlo per memorizzare i dati nel cache.

NCache fornisce una soluzione di cache distribuito che può essere installato su server Windows e Linux. Crearemo un cluster di cache utilizzando NCache e lo configureremo. Una volta impostato il cluster di cache, potremo connetterci a questo da applicazioni Java.

Abilitazione di NCache come Cache a Livello Secondario in Hibernate

Una volta impostato il server NCache, possiamo configurare Hibernate per utilizzare NCache come provider di cache a livello secondario. Aggiorniamo il file di configurazione di Hibernate e specificiamo le impostazioni di cache per abilitare il caching.

Abilitazione delle Regioni di Cache

Aggiorniamo le impostazioni del cache nel file hibernate.cfg.xml per abilitare NCache come provider di cache a livello secondario:

<hibernate-configuration> <session-factory> <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.region.factory_class">com.alachisoft.ncache.NCacheRegionFactory</property> ... </session-factory> </hibernate-configuration>

Qui, impostiamo la proprietà hibernate.cache.use_second_level_cache a true per abilitare il cache a livello secondario. Inoltre, specificiamo la proprietà hibernate.cache.region.factory_class per usare la NCacheRegionFactory, una implementazione della JCacheRegionFactory, come provider di cache.

Configurazione delle proprietà di NCache

NCache fornisce un insieme di proprietà per configurare le impostazioni del cache in Hibernate. Possiamo specificarle nel file ncache-hibernate.xml:

<configuration> <application-config application-id="myapp" enable-cache-exception="true" default-region-name="DefaultRegion" key-case-sensitivity="false"> <cache-regions> <region name="CustomerRegion" cache-name="demoCache" priority="AboveNormal" expiration-type="Sliding" expiration-period="8"/> <region name="DefaultRegion" cache-name="demoCache" priority="default" expiration-type="None" expiration-period="0"/> </cache-regions> <database-dependencies> <dependency entity-name="hibernator.BLL.Customer" type="oledb" sql-statement="SELECT CustomerID FROM Customers WHERE CustomerID ='?';" cache-key-format="Customers#[pk]" connection-string="Provider=SQLOLEDB;Data Source=20.200.20.40,1433;Initial Catalog=Northwind;User ID=john;Password=1234;"/> </database-dependencies> </application-config> </configuration>

In questo file di configurazione, definiamo la regione di cache CustomerRegion con nome cache, priorità, tipo di scadenza e periodo di scadenza. Impostiamo l’expiration-type a Sliding con un periodo di scadenza di 8 secondi. Questo significa che i dati nel cache scadranno dopo 8 secondi di inattività e verranno rimossi dal cache.

Inoltre, definiamo una DefaultRegion con impostazioni predefinite per altre entità che non hanno una regione di cache specifica. Questa viene utilizzata come regione di fallback per entità che non sono configurate esplicitamente.

Haver multipli regioni di cache ci consente di definire differenti impostazioni di cache per differenti entità in base alle loro necessità.

Successivamente, definiamo una dipendenza dati per l’entità Customers. Questo è usato per mantenere il cache sincronizzato con il database e aggiornare/rimuovere i dati in cache quando viene fatto un cambiamento nel database.

Specificiamo l’istruzione SQL per recuperare il CustomerID dalla tabella Customers e la stringa di connessione per connettersi al database.

Il formato della chiave cache specifica come viene generata la chiave cache in base alla chiave primaria dell’entità.

Test

Ora che abbiamo configurato NCache come cache secondo livello in Hibernate, proviamo l’applicazione per vedere come il caching migliora le prestazioni. Eseguiremmo di nuovo la classe client e osservereremmo le interazioni del database con il caching abilitato.

Quando facciamo partire la classe client, vedremo che la prima chiamata per recuperare l’oggetto Customer colpisce il database per ottenere i dati. Tuttavia, la seconda chiamata per recuperare lo stesso oggetto lo otterrà dalla cache invece di colpire di nuovo il database. Questo dimostra come il caching riduca il carico del database e migliora le prestazioni servendo i dati dalla cache.

Benefici dell’Uso di NCache con Hibernate

L’uso di NCache come cache secondo livello in Hibernate offre diversi benefici:

  • Impostazioni di rendering migliorate: NCache fornisce un’archiviazione in memoria rapida per i dati nel cache, riducendo la latenza e migliorando la throughput. Fornisce anche operazioni asincrone per aggiornare il cache in background, riducendo l’impatto sulle prestazioni dell’applicazione.
  • Scalabilità: Con l’aumento della scala dell’applicazione, NCache può scalare orizzontalmente per gestire grandi quantità di dati e richieste utente. Può essere distribuito in un cluster e supporta funzionalità come la replica del cache e la partizionamento per distribuire il carico.
  • Flessibilità: NCache fornisce varie topologie di cache e configurazioni per soddisfare i requisiti differenti delle applicazioni. Inoltre, grazie all’utilizzo di aree di cache, differenti entità possono avere impostazioni di cache differenti in base alle loro necessità. Questo consente un controllo granulare sul comportamento del cache.
  • Sincronizzazione: NCache offre come opzione la sincronizzazione del database per mantenere il cache in sincronia con il database. Questo garantisce che i dati nel cache siano aggiornati e riflettano gli ultimi cambiamenti apportati al database.

Riepilogo

In questo tutorial, abbiamo esplorato la realizzazione di un cache a livello secondario in Hibernate utilizzando NCache per applicazioni Java.

Abbiamo iniziato imparando le basi di Hibernate, NCache e il cache a livello secondario di Hibernate. Poi, abbiamo configurato un’applicazione Java con Hibernate e abbiamo configurato NCache come cache a livello secondario. Infine, abbiamo testato l’implementazione per vedere come il caching migliora le prestazioni riducendo i contatti col database e servendo i dati dal cache.

Utilizzando NCache con Hibernate, i developer possono migliorare le prestazioni, la scalabilità e la affidabilità delle loro applicazioni sfruttando il potere del caching distribuito. NCache fornisce una soluzione di caching robusta che integra in modo fluido Hibernate e altri framework Java, rendendola una scelta ideale per il caching dei dati nelle applicazioni Java.

Source:
https://dzone.com/articles/implement-hibernate-second-level-cache-with-ncache