Bienvenido al Tutorial de Ejemplo de Caché de Primer Nivel de Hibernate. Recientemente, echamos un vistazo a la arquitectura de Hibernate, el mapeo de Hibernate y cómo usar HQL para ejecutar consultas SQL de manera orientada a objetos. Hoy analizaremos uno de los aspectos importantes de Hibernate: la Caché de Hibernate.
La Caché de Hibernate
La Caché de Hibernate puede ser muy útil para obtener un rendimiento rápido de la aplicación si se usa correctamente. La idea detrás de la caché es reducir el número de consultas a la base de datos, por lo tanto, reduciendo el tiempo de procesamiento de la aplicación. Hibernate viene con diferentes tipos de caché:
- Primera Caché de Nivel: La caché de primer nivel de Hibernate está asociada con el objeto de sesión. La caché de primer nivel de Hibernate está habilitada de forma predeterminada y no hay forma de deshabilitarla. Sin embargo, Hibernate proporciona métodos mediante los cuales podemos eliminar objetos seleccionados de la caché o limpiar completamente la caché. Cualquier objeto almacenado en una sesión no será visible para otras sesiones y cuando se cierre la sesión, todos los objetos en caché también se perderán.
- Segunda Caché de Nivel: La caché de segundo nivel de Hibernate está deshabilitada de forma predeterminada, pero podemos habilitarla mediante configuración. Actualmente, EHCache e Infinispan proporcionan implementaciones para la caché de segundo nivel de Hibernate y podemos usarlas. Exploraremos esto en el próximo tutorial sobre el almacenamiento en caché de Hibernate.
- Caché de Consultas: Hibernate también puede almacenar en caché el conjunto de resultados de una consulta. La Caché de Consultas de Hibernate no almacena en caché el estado real de las entidades en la caché; solo almacena valores de identificador y resultados de tipos de valor. Por lo tanto, siempre debe usarse en conjunto con la caché de segundo nivel.
Almacenamiento en Caché de Hibernate – Ejemplo de Caché de Primer Nivel
Para mi programa de ejemplo de la caché de primer nivel de Hibernate, estoy utilizando la misma configuración que en Ejemplo de HQL, puedes revisarlo y configurar las tablas y llenarlas con datos ficticios. Primero veamos el programa, su salida y luego repasaremos algunos de los puntos importantes relacionados con la Caché de Primer Nivel de Hibernate. HibernateCacheExample.java
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateCacheExample {
public static void main(String[] args) throws InterruptedException {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
//Obtener empleado con id=1
Employee emp = (Employee) session.load(Employee.class, new Long(1));
printData(emp,1);
//Esperando un tiempo para cambiar los datos en el backend
Thread.sleep(10000);
//Obtener los mismos datos nuevamente, revisar los logs que no se ha ejecutado ninguna consulta
Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
printData(emp1,2);
//Crear nueva sesión
Session newSession = sessionFactory.openSession();
//Obtener empleado con id=1, notice the logs for query
Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1));
printData(emp2,3);
//INICIO: ejemplo de evicción para eliminar un objeto específico de la caché de primer nivel de hibernate
//Obtener empleado con id=2, primera vez por lo tanto consulta en los logs
Employee emp3 = (Employee) session.load(Employee.class, new Long(2));
printData(emp3,4);
//evictar el objeto empleado con id=1
session.evict(emp);
System.out.println("Session Contains Employee with id=1?"+session.contains(emp));
//como el objeto ha sido eliminado de la caché de primer nivel, verás una consulta en los logs
Employee emp4 = (Employee) session.load(Employee.class, new Long(1));
printData(emp4,5);
//este objeto todavía está presente, por lo que no verás una consulta en los logs
Employee emp5 = (Employee) session.load(Employee.class, new Long(2));
printData(emp5,6);
//FIN: ejemplo de evicción
//INICIO: ejemplo de limpieza para eliminar todo de la caché de primer nivel
session.clear();
Employee emp6 = (Employee) session.load(Employee.class, new Long(1));
printData(emp6,7);
Employee emp7 = (Employee) session.load(Employee.class, new Long(2));
printData(emp7,8);
System.out.println("Session Contains Employee with id=2?"+session.contains(emp7));
tx.commit();
sessionFactory.close();
}
private static void printData(Employee emp, int count) {
System.out.println(count+":: Name="+emp.getName()+", Zipcode="+emp.getAddress().getZipcode());
}
}
Cuando ejecutamos el ejemplo anterior, la salida contiene mucha información relacionada con Hibernate. Pero estamos principalmente interesados en la salida específica de nuestro código y las consultas ejecutadas por Hibernate para cargar los datos. El fragmento de salida se ve así.
Hibernate Configuration loaded
Hibernate serviceRegistry created
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
1:: Name=Pankaj, Zipcode=95129
2:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
3:: Name=PankajK, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
4:: Name=David, Zipcode=95051
Session Contains Employee with id=1?false
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
5:: Name=Pankaj, Zipcode=95129
6:: Name=David, Zipcode=95051
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
7:: Name=Pankaj, Zipcode=95129
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
8:: Name=David, Zipcode=95051
Session Contains Employee with id=2?true
Principales puntos sobre la Caché de Primer Nivel en Hibernate
Puntos importantes sobre la caché de primer nivel en Hibernate que se pueden derivar del programa anterior son:
- La caché de primer nivel de Hibernate está habilitada de forma predeterminada, no se necesitan configuraciones para esto.
- La caché de primer nivel de Hibernate es específica de la sesión, por eso, cuando obtenemos los mismos datos en la misma sesión, no se realiza ninguna consulta, mientras que en otra sesión se realiza una consulta para cargar los datos.
- La caché de primer nivel de Hibernate puede contener valores antiguos, como se puede ver arriba, he puesto mi programa en pausa durante 10 segundos y en ese tiempo actualicé el valor (nombre de Pankaj a PankajK) en la base de datos, pero no se reflejó en la misma sesión. Pero en otra sesión, obtuvimos el valor actualizado.
- Podemos usar el método
evict()
de la sesión para eliminar un solo objeto de la caché de primer nivel de Hibernate. - Podemos usar el método
clear()
de la sesión para limpiar la caché, es decir, eliminar todos los objetos de la caché. - Podemos usar el método
contains()
de la sesión para verificar si un objeto está presente en la caché de Hibernate o no, si se encuentra en la caché, devuelve true, de lo contrario, devuelve false. - Dado que Hibernate almacena todos los objetos en la caché de primer nivel de la sesión, al ejecutar consultas masivas o actualizaciones por lotes, es necesario limpiar la caché en ciertos intervalos para evitar problemas de memoria.
Eso es todo para el ejemplo de caché de hibernate y caché de primer nivel, en futuras publicaciones investigaremos la implementación de Caché de Segundo Nivel de Hibernate – EHCache .
Source:
https://www.digitalocean.com/community/tutorials/hibernate-caching-first-level-cache