Hibernate: almacenamiento en caché

El almacenamiento en caché es un mecanismo para mejorar el rendimiento de un sistema. Es una memoria intermedia que se encuentra entre la aplicación y la base de datos. La memoria caché almacena elementos de datos usados ​​recientemente para reducir el número de accesos a la base de datos tanto como sea posible.

El almacenamiento en caché también es importante para Hibernate. Utiliza un esquema de almacenamiento en caché multinivel como se explica a continuación:

Caché de primer nivel

El caché de primer nivel es el caché de sesión y es un caché obligatorio a través del cual deben pasar todas las solicitudes. El objeto Session mantiene un objeto bajo su propio poder antes de enviarlo a la base de datos.

Si emite varias actualizaciones a un objeto, Hibernate intenta retrasar la actualización tanto como sea posible para reducir la cantidad de declaraciones SQL de actualización emitidas. Si cierra la sesión, todos los objetos que se almacenan en caché se pierden y se conservan o se actualizan en la base de datos.

Caché de segundo nivel

La caché de segundo nivel es una caché opcional y la caché de primer nivel siempre se consultará antes de intentar ubicar un objeto en la caché de segundo nivel. El caché de segundo nivel se puede configurar por clase y por colección y es principalmente responsable del almacenamiento en caché de los objetos entre sesiones.

Se puede usar cualquier caché de terceros con Hibernate. Unorg.hibernate.cache.CacheProvider Se proporciona una interfaz, que debe implementarse para proporcionar a Hibernate un identificador para la implementación de la caché.

Caché de nivel de consulta

Hibernate también implementa una caché para conjuntos de resultados de consultas que se integra estrechamente con la caché de segundo nivel.

Esta es una característica opcional y requiere dos regiones de caché físicas adicionales que contienen los resultados de la consulta en caché y las marcas de tiempo cuando una tabla se actualizó por última vez. Esto solo es útil para consultas que se ejecutan frecuentemente con los mismos parámetros.

La caché de segundo nivel

Hibernate usa la caché de primer nivel por defecto y no tiene nada que hacer para usar la caché de primer nivel. Vayamos directamente a la caché de segundo nivel opcional. No todas las clases se benefician del almacenamiento en caché, por lo que es importante poder deshabilitar la caché de segundo nivel.

La caché de segundo nivel de Hibernate se configura en dos pasos. Primero, debe decidir qué estrategia de concurrencia utilizar. Después de eso, configure la caducidad de la caché y los atributos de la caché física utilizando el proveedor de caché.

Estrategias de concurrencia

Una estrategia de concurrencia es un mediador, que es responsable de almacenar elementos de datos en la caché y recuperarlos de la caché. Si va a habilitar una caché de segundo nivel, tendrá que decidir, para cada clase y colección persistente, qué estrategia de concurrencia de caché utilizar.

  • Transactional - Utilice esta estrategia para datos de lectura mayoritaria donde es fundamental evitar datos obsoletos en transacciones simultáneas, en el raro caso de una actualización.

  • Read-write - Utilice nuevamente esta estrategia para datos de lectura mayoritaria donde es fundamental evitar datos obsoletos en transacciones concurrentes, en el raro caso de una actualización.

  • Nonstrict-read-write- Esta estrategia no garantiza la coherencia entre la caché y la base de datos. Utilice esta estrategia si los datos casi nunca cambian y una pequeña probabilidad de datos obsoletos no es una preocupación crítica.

  • Read-only- Una estrategia de concurrencia adecuada para datos, que nunca cambia. Úselo solo para datos de referencia.

Si vamos a utilizar el almacenamiento en caché de segundo nivel para nuestro Employee class, agreguemos el elemento de mapeo requerido para decirle a Hibernate que almacene en caché las instancias de Empleado usando la estrategia de lectura y escritura.

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

El atributo use = "lectura-escritura" le dice a Hibernate que use una estrategia de concurrencia de lectura-escritura para la caché definida.

Proveedor de caché

Su próximo paso después de considerar las estrategias de simultaneidad, utilizará sus clases candidatas de caché para elegir un proveedor de caché. Hibernate te obliga a elegir un único proveedor de caché para toda la aplicación.

No Señor. Nombre y descripción de la caché
1

EHCache

Puede almacenar en caché en la memoria o en el disco y el almacenamiento en caché en clúster y es compatible con la caché de resultados de consultas Hibernate opcional.

2

OSCache

Admite el almacenamiento en caché en memoria y disco en una sola JVM con un amplio conjunto de políticas de caducidad y soporte de caché de consultas.

3

warmCache

Una caché de clúster basada en JGroups. Utiliza la invalidación agrupada, pero no es compatible con la caché de consultas de Hibernate.

4

JBoss Cache

Una caché en clúster replicada completamente transaccional también basada en la biblioteca de multidifusión JGroups. Admite replicación o invalidación, comunicación sincrónica o asincrónica y bloqueo optimista y pesimista. Se admite la caché de consultas de Hibernate.

Todos los proveedores de caché no son compatibles con todas las estrategias de simultaneidad. La siguiente matriz de compatibilidad le ayudará a elegir una combinación adecuada.

Estrategia / Proveedor Solo lectura Lectura-escritura no estricta Leer escribir Transaccional
EHCache X X X  
OSCache X X X  
SwarmCache X X    
Caché de JBoss X     X

Especificará un proveedor de caché en el archivo de configuración hibernate.cfg.xml. Elegimos EHCache como nuestro proveedor de caché de segundo nivel -

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

Ahora, debe especificar las propiedades de las regiones de caché. EHCache tiene su propio archivo de configuración,ehcache.xml, que debe estar en CLASSPATH de la aplicación. Una configuración de caché en ehcache.xml para la clase Empleado puede verse así:

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

Eso es todo, ahora tenemos el almacenamiento en caché de segundo nivel habilitado para la clase Empleado e Hibernate, ahora llega al caché de segundo nivel cada vez que navega a un Empleado o cuando carga un Empleado por identificador.

Debe analizar todas las clases y elegir la estrategia de almacenamiento en caché adecuada para cada una de las clases. En algún momento, el almacenamiento en caché de segundo nivel puede degradar el rendimiento de la aplicación. Por lo tanto, se recomienda comparar su aplicación primero, sin habilitar el almacenamiento en caché y luego habilitar el almacenamiento en caché adecuado y verificar el rendimiento. Si el almacenamiento en caché no mejora el rendimiento del sistema, no tiene sentido habilitar ningún tipo de almacenamiento en caché.

La caché de nivel de consulta

Para usar la caché de consultas, primero debe activarla usando el hibernate.cache.use_query_cache="true"propiedad en el archivo de configuración. Al establecer esta propiedad en true, hace que Hibernate cree las cachés necesarias en la memoria para contener la consulta y los conjuntos de identificadores.

A continuación, para utilizar la caché de consultas, utilice el método setCacheable (booleano) de la clase Query. Por ejemplo

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

Hibernate también admite un soporte de caché muy detallado a través del concepto de una región de caché. Una región de caché es parte de la caché que tiene un nombre.

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

Este código usa el método para decirle a Hibernate que almacene y busque la consulta en el área de empleados de la caché.