среда, 9 декабря 2015 г.

Кэширование в hibernate

На днях столкнулся с задачей кэширования запросов к БД. Приложение использовало, как это не странно, hibernate. В этой статье я расскажу, о том какие бывают кэши в hibernate, каким образом их использовать и как настраивать.

Начнем по порядку.
Всего в hibernate существует три вида кэша:

  1. сессионый,
  2. кэш sessionFactory или же кеш второго уровня и
  3. кэш запросов

Сессионый кэш, исходя из названия, используются в рамках одной сессии. Для каждой сессии свой кэш, как только сессия закрывается - он очищается. Для ясности, приведу пример :

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

Кэш второго уровня или sessionFactory кэш распространяется на все сессии. По умолчанию, выключен. Чтобы включить нужно добавить в зависимости библиотеку предоставляющую его реализацию. Я использовал ehcache. Оговорюсь сразу, что все настройки применимы для hibernate версии 4.0 и выше

И добавить в конфигурацию hibernate следующие:

Параметры для кэшей в Ehcache задаются в отдельном файле echache.xml

Флаг eternal, показывает, хотим ли мы переопределить параметры timeToIdleSeconds, timeToLiveSeconds. Если выставлен true, то значения игнорируются и объекты в кэше никогда не удаляются. Стоит обратить внимание на параметр path в diskStore, он указывает путь до директории, где будут храниться файлы кэша. Значение java.io.tmpdir - путь до стандартной папки с временными файлами без привязки к операционной системе.

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

Если аннотациями, то следует добавить рядом с @Entity следующее: @Cache(usage = CacheConcurrencyStrategy.READ_WRITE).
Следует уточнить еще один момент, в качестве значений может быть следующие:

  1. read-write в зависимости от уровня транзакции, обновление объектов происходит согласно правилам read committed или же repeatable read. Данная стратегия является компромиссом при многопоточном доступе и частом обновлении информации.
  2. nonstrict-read-write применимо для объектов, которые подвержены изменениям, происходит это без блокировки кеша, при возможности предоставляется доступ к объекту из разных потоков, но тогда при этом не гарантируется что будет получена самая последняя версия объекта
  3. read-only используется для объектов, которые никогда не изменяются

Чтобы включить кэширование для запросов, нужно так же добавить зависимости, указать параметры в файле echache.xml и разрешить кэширование запросов в hibernate.properties:

Теперь, для тех запросов, результаты которых должны попадать в кэш, нужно вызвать метод setCacheable(true), если используется Criteria или запросы HQL.