JavaRush /Курсы /Модуль 4. Работа с БД /Настройка кэша запросов

Настройка кэша запросов

Модуль 4. Работа с БД
14 уровень , 6 лекция
Открыта

Зачем нужен кэш запросов

Перепишем наш пример с получением сотрудников на HQL:


Employee director1 = session.createQuery("from Employee where id = 4").uniqueResult();
Employee director2 = session.createQuery("from Employee where id = 4").uniqueResult();
 
assertTrue(director1 != director2);

Результаты такого рода запросов не сохраняются кэшем ни первого, ни второго уровня.

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

<property name="hibernate.cache.use_query_cache" value="true"/>

Но это только половина решения. Кэш запросов мы включили, но нам нужно еще и указать, результаты каких запросов мы хотим кэшировать. Это нужно прописать в запросе Query:


Query query = session.createQuery("from Employee where id = 4");
query.setCacheable(true);
Employee director1 = query.uniqueResult();

Кэш запросов похож на кэш второго уровня. Но, в отличии от него, тут ключом к данным кэша выступает не идентификатор объекта, а совокупность параметров запроса. А сами данные — это идентификаторы объектов, соответствующих критериям запроса. Таким образом этот кэш рационально использовать с кэшем второго уровня.

Очистка кэша

Одна из важных задач при работе с кэшем — это следить за тем, чтобы кэшируемые объекты изменились, и удалять их из кэша (или обновлять). Hibernate делает это очень даже успешно. Иногда даже кажется, что он руководствуется правилом “в любой непонятной ситуации очищай кэш”.

Допустим, ты хочешь обновить данные пользователя через HQL:


Query query = session.createQuery("update Employee set name=’Alex’ where id = 4")
query. executeUpdate();

Hibernate не может точно знать, что в базе поменялось, но он знает, что ты меняешь объект типа Employee. Поэтому после выполнения этого запроса Hibernate удалит из своего кэша вообще все объекты типа Employee.

Но еще интересней работает NativeQuery:


Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4")
nativeQuery.executeUpdate();

Выполнился родной SQL-запрос к базе данных. А значит, в базе данных что-то поменялось — запрос-то вызван в методе executeUpdate(). Поэтому в этом случае Hibernate немного перестрахуется и удалит из своего кэша вообще все объекты всех типов.

Как тебе такое? Ты вызываешь безобидный запрос, а Hibernate в ответ стирает все данные из кэша! Это конечно лучше, чем если бы он хранил у себя объекты, которые отличаются от базы, но такое!

Поэтому создатели Hibernate быстро придумали, как помочь Hibernate в этом случае. Ты можешь указать ему, какой тип сущностей нужно удалить из кэша:


Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4");
nativeQuery.unwrap(org.hibernate.SQLQuery.class).addSynchronizedEntityClass(Employee.class);
nativeQuery.executeUpdate();
Замечание. Нативные select-запросы не сбрасывают кэш, только insert, update, delete, вызовы процедур и т. п.

Ручная очистка кэша

По определенным причинам ты можешь захотеть удалить объект из кэша самостоятельно. Сделать это можно разными способами.

Примечание. Объекты в кэше сохраняются группами, которые называются регионами. По умолчанию имя региона совпадает с именем класса. Поэтому если у тебя есть объекты типа com.javarush.Employee, то все они будут сохранены в группу (регион) с именем “com.javarush.employee”.

Если ты хочешь получить доступ к кэшу и что-то с ним сделать, то это можно сделать с помощью объекта SessionFactory и метода getCache():


session.getSessionFactory().getCache().evictQueryRegion("com.javarush.employee”);

Если ты хотчешь удалить данные из всех групп (регионов), то нужно выполнить такой запрос:


session.getSessionFactory().getCache().evictAllRegions();

Чтобы удалить один объект из кэша, нужно передать его имя (тип) и id. Сделать это можно двумя способами:


session.getSessionFactory().getCache().evictEntityData("Employee”, 4);
 
session.getSessionFactory().getCache().evictEntityData(com.javarush.Employee.class, 4);

Также ты можешь проверить, содержится ли определенный объект в кэше:


session.getSessionFactory().getCache().containsEntity("Employee”, 4);
session.getSessionFactory().getCache().containsEntity(com.javarush.Employee.class, 4);
1
Задача
Модуль 4. Работа с БД, 14 уровень, 6 лекция
Недоступна
Кеш запросов
Для этой задачи тебе понадобиться дополнительная зависимость, которую можно скачать здесь: https://repo1.maven.org/maven2/org/hibernate/hibernate-ehcache/5.6.11.Final/hibernate-ehcache-5.6.11.Final.jar
Комментарии (13)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Мая Уровень 82
3 ноября 2025
Может кому понадобится бесплатный курс по hibernate, нашла на Stepik: https://stepik.org/course/246959/syllabus
Иван Корниенко Уровень 109
15 августа 2024
Руслан Уровень 115
25 июля 2024
В задаче, где мы якобы должны скачать зависимость "здесь" - ссылка не работает!!!
Павел Уровень 19 Expert
2 апреля 2024
Это про лекцию.

<property name="hibernate.cache.use_query_cache" value="true"/>
наличие или отсутствие этой настройки у меня никак не влияет на assertTrue(director1 != director2). Можно даже написать

query.setCacheable(false);
assertTrue все время получает true. Почему бы это?
Ольга Николенко Уровень 109 Expert
8 июня 2024
у вас написана настройка для подключение кэша запросов (кэш третьего уровня), но пример из лекции про кэш второго уровня если верить лекциям (я пока сама не проверяла) - тут зависит от того какой запрос вы выполняете и подключили ли вы кэширование для конкретного запроса плюс, возможно, необходимо разобраться в конфигурации выбранной реализации движка кэширования
Max Dudin Уровень 6 Expert
14 октября 2023
что-то уже не и сил бодаться с этим всем...
Misha Saharin Уровень 111 Expert
16 мая 2023
is it here?
Sergey Drogunov Уровень 111 Expert
22 декабря 2022
Поехало только после добавления 3х зависимостей. https://mvnrepository.com/artifact/net.sf.ehcache/ehcache/2.10.9.2 https://mvnrepository.com/artifact/javax.transaction/javax.transaction-api/1.3 https://mvnrepository.com/artifact/org.slf4j/slf4j-api/2.0.6 Очень жаль, что это выяснено методом тыка, и без ясности почему такая зависимость
Pavel Petrov Уровень 109 Expert
3 февраля 2023
помогло добавление зависимостей + изменение SQL диалекта на org.hibernate.dialect.MySQL8Dialect + добавление строчки в MySessionFactory properties.put(Environment.HBM2DDL_AUTO, "update"); а так же изменение конфига подключения к базе, нужно чтобы была пустая схема test UPD: если изменять класс MySessionFactory, не будет проходить валидация, поэтому действия с изменением лучше выполнять после проверки задачи
jvatechs Уровень 111 Expert
4 октября 2023
Также получилось запустить лишь с добавлением этих изменений.
Nikita Shamrai Уровень 8 Expert
8 декабря 2022
Задача не запускается после добавления зависимости. Exception in thread "main" java.lang.NoClassDefFoundError: net/sf/ehcache/CacheException at java.lang.Class.getDeclaredConstructors0(Native Method) at java.lang.Class.privateGetDeclaredConstructors(Class.java:2699) at java.lang.Class.getConstructor0(Class.java:3103) at java.lang.Class.getConstructor(Class.java:1853) at ........
Sergey Drogunov Уровень 111 Expert
22 декабря 2022
Тоже не смог запустить, в конфигурациях не может найти вот это:

properties.put(Environment.CACHE_REGION_FACTORY, "org.hibernate.cache.ehcache.internal.EhcacheRegionFactory");
Руслан Уровень 115
25 июля 2024
+1, так и не смог запустить!