Implementar el caché de segundo nivel de Hibernate con NCache

En este tutorial, exploraremos la implementación de un caché de segundo nivel en Hibernate usando NCache.

Configuraremos una aplicación de Java con Hibernate. A continuación, configuraremos NCache como caché de segundo nivel. Finalmente, probaremos la implementación para ver cómo el caching reduce la carga de la base de datos y mejora el rendimiento.

Basicos

Antes de sumergirnos en la implementación, vamos a comprender los conceptos básicos de Hibernate, NCache y el caché de segundo nivel de Hibernate.

Hibernate

Hibernate es una herramienta de mapeo objeto-relacional (ORM) de código abierto para aplicaciones Java. Simplifica la interacción con bases de datos mediante el mapeado de objetos Java a tablas de base de datos y viceversa.

Para mejorar el rendimiento, Hibernate proporciona dos niveles de caching:

1. Caché de Primer Nivel

El caché de primer nivel se asocia con la sesión de Hibernate y está habilitado de forma predeterminada. Almacena los objetos recuperados durante una sesión y elimina la necesidad de acceder a la base de datos varias veces para el mismo objeto.

El caché de primer nivel está limitado al ámbito de una sesión y no se comparte entre sesiones.

También no es persistente y se limpia cuando se cierra o limpia explícitamente la sesión.

2. Caché de Segundo Nivel

La caché de segundo nivel se comparte entre sesiones y se puede configurar para cachear datos a nivel de aplicación. Reduce el número de consultas a la base de datos almacenando objetos por un período más largo.

La caché de segundo nivel necesita ser configurada explicitamente y se puede implementar utilizando varios proveedores de caché como NCache, Ehcache, etc.

NCache

NCache es una solución de caché distribuida para aplicaciones .NET y Java. Proporciona una tienda de datos en memoria que se puede utilizar para cachear datos accedidos frecuentemente y mejorar el rendimiento de las aplicaciones.

NCache admite varias topologías de caché como replicadas, particionadas y caché cliente.

NCache se puede utilizar como caché de segundo nivel en Hibernate para almacenar y recuperar objetos del caché en lugar de consultar la base de datos.

Configuración del código

Empecemos creando una aplicación Java y configurando Hibernate para interactuar con la base de datos.

Usaremos Maven para gestionar las dependencias y construir el proyecto. La aplicación tendrá una clase de entidad para definir los datos y una clase de cliente para interactuar con la base de datos.

Primero, probaremos la aplicación sin caché para ver las interacciones con la base de datos. A continuación, configuraremos NCache como caché de segundo nivel en Hibernate para cachar los objetos de entidad y reducir las consultas a la base de datos.

Dependencias

Comencemos agregando las dependencias requeridas para Hibernate y NCache en el archivo 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>

Tenga en cuenta que las versiones mencionadas aquí pueden variar en función de las últimas publicaciones. Asegúrese de utilizar las versiones apropiadas para su proyecto.

Clase de Entidad

Después, vamos a crear una clase de entidad para representar los datos que queremos cachear. Definiremos una simple clase Cliente con campos id y nombre:

@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 clase Cliente está anotada con @Entity y @Cacheable para definirla como una entidad cachable. Tiene un campo id anotado con @Id y @GeneratedValue para generar identificadores únicos automáticamente.

También utilizamos la anotación @Cache para especificar la estrategia de caché y la región para la entidad.

NONSTRICT_READ_WRITE le dice a Hibernate que actualice el caché cuando se lean o escriban datos con eventualidad de consistencia.

El atributo region especifica la región de caché donde se almacenarán los datos.

Configuraremos NCache para utilizar esta región para almacenar los datos en caché.

Configuración de Hibernate

Necesitamos configurar Hibernate para interactuar con la base de datos y habilitar el caching.

Vamos a crear un archivo hibernate.cfg.xml en el directorio src/main/resources con la siguiente configuración:

<?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>

En este archivo de configuración, especificamos los detalles de conexión a la base de datos, el dialecto y las configuraciones de caché. Utilizamos Oracle como base de datos y configuramos Hibernate para actualizar el esquema automáticamente.

Clase del Cliente

Vamos a crear una clase de cliente para interactuar con la base de datos y probar el mecanismo de caché. Podemos escribir una clase main para guardar y recuperar objetos de Customer utilizando 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(); } }

En esta clase de cliente, creamos una SessionFactory utilizando la configuración de Hibernate y abrimos una sesión para interactuar con la base de datos. Guardamos un objeto de Customer en la base de datos y lo recuperamos utilizando el id.

A continuación, llamamos a la función retrieveCustomer dos veces en dos sesiones separadas para ver las interacciones con la base de datos sin caché.

Veremos que se realiza una consulta a la base de datos dos veces para recuperar el mismo objeto:

Como podemos ver, se ejecuta la consulta de Hibernate dos veces.

Configuración del Servidor NCache

Para utilizar NCache como caché de segundo nivel en Hibernate, necesitamos configurar un servidor NCache y configurarlo para almacenar los datos en caché.

NCache proporciona una solución de caché distribuida que puede instalarse en servidores Windows y Linux. Creamos un cluster de caché utilizando NCache y lo configuramos. Una vez que se ha configurado el cluster de caché, podemos conectarnos a él desde nuestra aplicación Java.

Habilitación de NCache como proveedor de caché de segundo nivel en Hibernate

Una vez configurado el servidor NCache, podemos configurar Hibernate para utilizar NCache como proveedor de caché de segundo nivel. Actualizaremos el archivo de configuración de Hibernate y especificaremos los ajustes de caché para habilitar el caché.

Habilitación de las regiones de caché

Actualizemos las configuraciones de caché en el archivo hibernate.cfg.xml para habilitar NCache como proveedor de caché de nivel dos:

<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>

Aquí, establecemos la propiedad hibernate.cache.use_second_level_cache a true para habilitar la caché de nivel dos. También especificamos la propiedad hibernate.cache.region.factory_class para usar la NCacheRegionFactory, una implementación de JCacheRegionFactory, como proveedor de caché.

Configurando las Propiedades de NCache

NCache proporciona un conjunto de propiedades para configurar los ajustes de caché en Hibernate. Podemos especificar estos en el archivo 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>

En este archivo de configuración, definimos la región de caché CustomerRegion con el nombre de caché, la prioridad, el tipo de expiración y el período de expiración. Establecemos el expiration-type a Sliding con un período de expiración de 8 segundos. Esto significa que los datos en caché expirarán después de 8 segundos de inactividad y se eliminarán de la caché.

Además, definimos una DefaultRegion con configuraciones predeterminadas para otras entidades que no tienen una región de caché específica. Esto se utiliza como una región de fallback para entidades que no están configuradas explícitamente.

Tener varias regiones de caché nos permite definir diferentes configuraciones de caché para diferentes entidades según sus requisitos.

A continuación, definimos una dependencia de base de datos para la entidad Customers. Esto se utiliza para mantener sincronizado el caché con la base de datos y actualizar/eliminar los datos en caché cuando se realizan cambios en la base de datos.

Especificamos la sentencia SQL para recuperar el CustomerID de la tabla Customers y la cadena de conexión para conectarnos a la base de datos.

El formato de la clave de caché especifica cómo se genera la clave de caché basándose en la clave primaria de la entidad.

Pruebas

Ahora que hemos configurado NCache como caché de nivel dos en Hibernate, vamos a probar la aplicación para ver cómo se mejora el rendimiento con el uso de caché. Ejecutaremos de nuevo la clase cliente y observaremos las interacciones con la base de datos con el caché habilitado.

Cuando ejecutamos la clase cliente, veremos que la primera llamada para recuperar el objeto Customer impacta en la base de datos para obtener los datos. Sin embargo, la segunda llamada para recuperar el mismo objeto lo obtendrá del caché en lugar de impactar en la base de datos de nuevo. Esto demuestra cómo el caché reduce la carga de la base de datos y mejora el rendimiento al servir datos del caché.

Beneficios del Uso de NCache con Hibernate

El uso de NCache como caché de nivel dos en Hibernate ofrece varios beneficios:

  • Mejor rendimiento: NCache proporciona un almacenamiento en memoria rápido para datos en caché, reduciendo la latencia y mejorando la throughput. También ofrece operaciones asíncronas para actualizar la caché en segundo plano, reduciendo el impacto en el rendimiento de la aplicación.
  • Escalabilidad: A medida que la aplicación se escala, NCache puede escalar horizontalmente para manejar grandes cantidades de datos y solicitudes de usuario. Puede implementarse en un clúster y admite características como la replicación de caché y la partición para distribuir la carga.
  • Flexibilidad: NCache ofrece varias topologías de caché y configuraciones para satisfacer diferentes necesidades de aplicaciones. Además, debido al uso de regiones de caché, diferentes entidades pueden tener diferentes configuraciones de caché en función de sus necesidades. Esto permite un control fino sobre el comportamiento de la caché.
  • Sincronización: NCache ofrece la opción de sincronización con la base de datos para mantener la caché sincronizada con la base de datos. Esto garantiza que los datos en caché están actualizados y reflejan las últimas modificaciones realizadas en la base de datos.

Resumen

En este tutorial, exploramos la implementación de un caché de nivel dos en Hibernate usando NCache para aplicaciones Java.

Comenzamos entendiendo los conceptos básicos de Hibernate, NCache y el caché de nivel dos de Hibernate. Luego, configuramos una aplicación Java con Hibernate y configuramos NCache como caché de nivel dos. Finalmente, probamos la implementación para ver cómo la caché mejora el rendimiento reduciendo los hitos en la base de datos y sirviendo datos directamente de la caché.

Al utilizar NCache con Hibernate, los desarrolladores pueden mejorar el rendimiento, la escalabilidad y la confiabilidad de sus aplicaciones, aprovechando el poder de caché distribuido. NCache ofrece una solución de caché robusta que se integra sin problemas con Hibernate y otros marcos Java, lo que lo convierte en una opción ideal para caché de datos en aplicaciones Java.

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