Кэширование Hibernate – Кэш первого уровня

Добро пожаловать в учебное пособие по примеру кеширования Hibernate – кеш первого уровня. Недавно мы изучили архитектуру Hibernate, отображение Hibernate и способы использования HQL для выполнения SQL-запросов в объектно-ориентированном стиле. Сегодня мы рассмотрим один из важных аспектов Hibernate – кеш Hibernate.

Кеширование Hibernate

Кеш Hibernate может быть очень полезен для повышения производительности приложения при правильном использовании. Идея кеша заключается в уменьшении количества запросов к базе данных, тем самым сокращая время пропускной способности приложения. Hibernate поставляется с различными типами кеша:

  1. Кеш первого уровня: Кеш первого уровня Hibernate связан с объектом Session. Кеш первого уровня Hibernate включен по умолчанию, и нет способа его отключить. Тем не менее, Hibernate предоставляет методы, с помощью которых можно удалить выбранные объекты из кеша или полностью очистить кеш. Любой объект, закешированный в сессии, не будет виден другим сессиям, и когда сессия закрывается, все закешированные объекты также будут утеряны.
  2. Кеш второго уровня: Кеш второго уровня Hibernate отключен по умолчанию, но мы можем включить его через конфигурацию. В настоящее время EHCache и Infinispan предоставляют реализацию кеша второго уровня для Hibernate, и мы можем использовать их. Об этом мы расскажем в следующем уроке по кешированию Hibernate.
  3. Кеш запросов: 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, которые можно выделить из приведенной выше программы:

  1. Первичный кеш Hibernate включен по умолчанию, для этого не требуется настроек.
  2. Первичный кеш Hibernate специфичен для сессии, поэтому при получении тех же данных в той же сессии запрос не выполняется, в то время как в другой сессии выполняется запрос для загрузки данных.
  3. Первичный кеш Hibernate может содержать старые значения, как видно выше, я приостановил выполнение программы на 10 секунд, и за это время я обновил значение (имя с Pankaj на PankajK) в базе данных, но это не отразилось в той же сессии. Но в другой сессии мы получили обновленное значение.
  4. Мы можем использовать метод evict() сессии для удаления одного объекта из первичного кеша Hibernate.
  5. Мы можем использовать метод clear() сессии для очистки кеша, то есть удаления всех объектов из кеша.
  6. Мы можем использовать метод contains() сессии, чтобы проверить, присутствует ли объект в кеше Hibernate или нет. Если объект найден в кеше, возвращается true, в противном случае возвращается false.
  7. Поскольку Hibernate кеширует все объекты в первичном кеше сессии, при выполнении массовых запросов или пакетных обновлений необходимо периодически очищать кеш, чтобы избежать проблем с памятью.

Это всё, что касается кэширования Hibernate и примера кэша первого уровня. В будущих сообщениях мы рассмотрим реализацию Кэша второго уровня Hibernate – EHCache.

Source:
https://www.digitalocean.com/community/tutorials/hibernate-caching-first-level-cache