Как работает кэш первого уровня в Hibernate? Примеры

Введение

Кэширование это возможность предоставляемая ORM фреймворками, которая помогает пользователям достичь высокую скорость, и в то же время помогает самим фреймворкам уменьшить количество обращений к БД. Hibernate достигает вторую цель вводя кэш первого уровня.

Кэш первого уровня в Hibernate включен по умолчанию и Вам не нужно ничего предпринимать, чтобы включить его. Даже выключить его не удастся. На самом деле, в роли кэша в сессии выступает Persistence Context. В приложении Hibernate, мы говорим что одна сессия имеет один внутренний persistence context. В JPA приложении, EntityManager имеет так же свой persistence context.

Persistence контекст полезен по нескольким причинам:

  • Hibernate может делать автоматические dirty checking и транзакции
  • Hibernate может использовать persistence контекст как кэш первого уровня
  • Hibernate может гарантировать уникальность Java-объекта в масштабе сессии
  • Слой persistence не уязвим к переполнениям стека в случае зацикленных ссылок в графе объектов
  • Никогда не может быть противоречивых представлений одной и той же строки в БД в конце единицы работы
  • Изменения совершенные в едином persistence контексте всегда видны сразу для всего остального исполняемого кода внутри persistence контекста и его единицы работы (гарантируются повторные чтения).

Легче понимать кэш первого уровня, если мы поймем тот факт, что он ассоциирован с объектом Session. Как мы знаем объект сессии создается по запросу от SessionFactory и кэш уничтожается в тот момент, когда сессия закрывается. Кэш первого уровня также называется Кэшем уровня сессии, означая что он работает для сессии только, в случае если один и тот же запрос будет выполнен два или более раз в одной сессии он выдаст данные из БД только для первого запроса и вернет те же самые данные из кэша для всех входящих подобных запросов.

Как работает кэширование первого уровня?

Кэш первого уровня связан с сессией только, когда запрос выполняется первый раз он выдает данные из БД и сохраняет результат запроса в кэш. Данные сохраненные в кэше при первом запросе будут выдываться и для всех входящих подобных запросов, пока сессия жива.

hibernate-first-level-caching

Как только сессия закроется весь кэш первого уровня будет очищен. Мы можем удалить частично загруженную сущность из кэша при помощи метода evict() и весь кэш может быть очищен используя метод clear(). Как только кэш очистится при вызове одного из двух методов свыше, он будет делать запрос к БД снова для нового вызова даже если сессия еще не закрыта.

Пример:


package ru.akorsa.sample;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import ru.akorsa.models.Employee;
import ru.akorsa.utils.HibernateUtils;
public class CachingImpl {
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();

// create an employee object to persist in DB
Employee employee = new Employee("eddy", "smith",
"eddy@akorsa.ru", "9898787676");

// lets save few data in Employee table
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(employee);
transaction.commit();
session.close();

System.out.println("****Data creation completed****");

Session session1 = sessionFactory.openSession();
System.out.println("****Created Session 1****");
transaction = session1.beginTransaction();

employee = (Employee) session1.load(Employee.class, 1l);
System.out.println(employee.getFirstName());

employee = (Employee) session1.load(Employee.class, 1l);
System.out.println(employee.getFirstName());

employee = (Employee) session1.load(Employee.class, 1l);
System.out.println(employee.getFirstName());

transaction.commit();
session1.close();
System.out.println("****Closed Session 1****");

Session session2 = sessionFactory.openSession();
System.out.println("****Created Session 2****");
transaction = session2.beginTransaction();

employee = (Employee) session2.load(Employee.class, 1l);
System.out.println(employee.getFirstName());

transaction.commit();
session2.close();
System.out.println("****Closed Session 2****");

}
}

Результат:

first-level-cache-example-1

Вы можете видеть, что в сессии под номер 1 мы запросили сущность три раза, но запрос в БД был выполнен только один раз и для второго и третьего запроса были получены данные сохраненные в кэше. Мы закрываем сессию 1 и открываем вторую сессию, в этот раз мы запросили эту же сущность из БД, но был сделан запрос прямо в БД, потому что кэшированные данные очистились, когда сессия 1 закрылась.

Как работают методы evict() и clear() в Hibernate

Мы не можем выключить кэш первого уровня в Hibernate, но мы можем удалить некоторую конкретную сущность из кэша с помощью evict() и весь кэш с помощью clear(). Пример ниже:


package ru.akorsa.sample;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import ru.akorsa.models.Employee;
import ru.akorsa.utils.HibernateUtils;
public class EvictImpl {
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();

// create an employee object to persist in DB
Employee employee = new Employee("eddy", "smith",
"eddy@beingjavaguys.com", "9898787676");

// lets save few data in Employee table
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(employee);
transaction.commit();
session.close();

System.out.println("****Data creation completed****");

Session session1 = sessionFactory.openSession();
System.out.println("****Created Session****");
transaction = session1.beginTransaction();

employee = (Employee) session1.load(Employee.class, 1l);
System.out.println(employee.getFirstName());

employee = (Employee) session1.load(Employee.class, 1l);
System.out.println(employee.getFirstName());

// removed employee entity from the cache
session1.evict(employee);
System.out.println("****removed employee entity from the cache****");

employee = (Employee) session1.load(Employee.class, 1l);
System.out.println(employee.getFirstName());

transaction.commit();
session1.close();
System.out.println("****Closed Session****");

}
}

Результат:

first-level-cache-example-2

(Visited 2 173 times, 1 visits today)

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.