Добро пожаловать в учебное пособие по примеру кеширования Hibernate – кеш первого уровня. Недавно мы изучили архитектуру Hibernate, отображение Hibernate и способы использования HQL для выполнения SQL-запросов в объектно-ориентированном стиле. Сегодня мы рассмотрим один из важных аспектов Hibernate – кеш Hibernate.
Кеширование Hibernate
Кеш Hibernate может быть очень полезен для повышения производительности приложения при правильном использовании. Идея кеша заключается в уменьшении количества запросов к базе данных, тем самым сокращая время пропускной способности приложения. Hibernate поставляется с различными типами кеша:
- Кеш первого уровня: Кеш первого уровня Hibernate связан с объектом Session. Кеш первого уровня Hibernate включен по умолчанию, и нет способа его отключить. Тем не менее, Hibernate предоставляет методы, с помощью которых можно удалить выбранные объекты из кеша или полностью очистить кеш. Любой объект, закешированный в сессии, не будет виден другим сессиям, и когда сессия закрывается, все закешированные объекты также будут утеряны.
- Кеш второго уровня: Кеш второго уровня Hibernate отключен по умолчанию, но мы можем включить его через конфигурацию. В настоящее время EHCache и Infinispan предоставляют реализацию кеша второго уровня для Hibernate, и мы можем использовать их. Об этом мы расскажем в следующем уроке по кешированию Hibernate.
- Кеш запросов: Hibernate также может кешировать набор результатов запроса. Кеш запросов Hibernate не кеширует состояние фактических сущностей в кеше; он кеширует только значения идентификаторов и результаты типа значения. Поэтому его всегда следует использовать совместно с кешем второго уровня.
Пример кеширования Hibernate – Кеш первого уровня
Для моей программы примера кэша первого уровня Hibernate я использую ту же конфигурацию, что и в Пример HQL. Вы можете проверить это и настроить таблицы, а также заполнить их фиктивными данными. Давайте сначала рассмотрим программу, её вывод, а затем мы пройдем через некоторые важные моменты, касающиеся кэша первого уровня 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();
//Получить сотрудника с id=1
Employee emp = (Employee) session.load(Employee.class, new Long(1));
printData(emp,1);
//Подождите некоторое время, чтобы изменить данные на бэкэнде
Thread.sleep(10000);
//Получить те же данные снова, проверить логи, что запрос не отправлен
Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
printData(emp1,2);
//Создать новую сессию
Session newSession = sessionFactory.openSession();
//Получить сотрудника с id=1, notice the logs for query
Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1));
printData(emp2,3);
//START: пример удаления для удаления конкретного объекта из кэша первого уровня Hibernate
//Получить сотрудника с id=2, первый раз, поэтому запрос в логах
Employee emp3 = (Employee) session.load(Employee.class, new Long(2));
printData(emp3,4);
//удалить объект сотрудника с id=1 из кэша
session.evict(emp);
System.out.println("Session Contains Employee with id=1?"+session.contains(emp));
//поскольку объект удален из кэша первого уровня, вы увидите запрос в логах
Employee emp4 = (Employee) session.load(Employee.class, new Long(1));
printData(emp4,5);
//этот объект все еще присутствует, поэтому вы не увидите запрос в логах
Employee emp5 = (Employee) session.load(Employee.class, new Long(2));
printData(emp5,6);
//END: пример удаления
//START: пример очистки для удаления всего из кэша первого уровня
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());
}
}
Когда мы запускаем приведенный выше пример, вывод содержит много информации, связанной с Hibernate. Но нас в основном интересует вывод нашего конкретного кода и запросы, отправляемые Hibernate для загрузки данных. Фрагмент вывода выглядит примерно так.
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
Первичный кеш в Hibernate: важные моменты
Важные моменты о первичном кеше в Hibernate, которые можно выделить из приведенной выше программы:
- Первичный кеш Hibernate включен по умолчанию, для этого не требуется настроек.
- Первичный кеш Hibernate специфичен для сессии, поэтому при получении тех же данных в той же сессии запрос не выполняется, в то время как в другой сессии выполняется запрос для загрузки данных.
- Первичный кеш Hibernate может содержать старые значения, как видно выше, я приостановил выполнение программы на 10 секунд, и за это время я обновил значение (имя с Pankaj на PankajK) в базе данных, но это не отразилось в той же сессии. Но в другой сессии мы получили обновленное значение.
- Мы можем использовать метод
evict()
сессии для удаления одного объекта из первичного кеша Hibernate. - Мы можем использовать метод
clear()
сессии для очистки кеша, то есть удаления всех объектов из кеша. - Мы можем использовать метод
contains()
сессии, чтобы проверить, присутствует ли объект в кеше Hibernate или нет. Если объект найден в кеше, возвращается true, в противном случае возвращается false. - Поскольку Hibernate кеширует все объекты в первичном кеше сессии, при выполнении массовых запросов или пакетных обновлений необходимо периодически очищать кеш, чтобы избежать проблем с памятью.
Это всё, что касается кэширования Hibernate и примера кэша первого уровня. В будущих сообщениях мы рассмотрим реализацию Кэша второго уровня Hibernate – EHCache.
Source:
https://www.digitalocean.com/community/tutorials/hibernate-caching-first-level-cache