Представляю вашему вниманию перевод шестой главы официальной документации Hibernate.
Перевод статьи актуален для версии Hibernate 4.2.19.Final
Предыдущая глава — Документация разработчика Hibernate – Глава V. Блокировки
Что собой представляют кэш первого и второго уровня в Hibernate, показано на следующий диаграмме (прим. автора).
Если у вас есть запросы, выполняющиеся снова и снова, с одними и теми же параметрами, кэширование запросов предоставит выигрыш в производительности.
Кэширование вводит дополнительные накладные расходы в области выполнения транзакций. К примеру, если вы кэшируете результаты запроса по отношению к какому-либо объекту, Hibernate необходимо отслеживать, были ли закоммичены какие-либо изменения по объекту, и в соответствии с этим, аннулировать записи в кэше. В дополнение, плюсы от кэширования запросов ограничены, и очень зависят от шаблонов использования вашего приложения. По этим причинам, Hibernate по-умолчанию выключает кэширование запросов.
Кэш запросов не кэширует состояние актуальных сущностей в кэше. Он кэширует значения идентификаторов и результаты типов. Таким образом, всегда используете кэш запросов в паре с кэшем второго уровня для тех сущностей, которые должны кэшироваться как часть кэша запросов.
Для лучшего контроля за политиками истечения актуальности у кэшей запросов, укажите именованный регион кэширования для определенного запроса, вызвав Query.setCacheRegion().
Пример 6.1. Метод setCacheRegion
Чтобы заставить кэш запросов обновить один из его регионов, и проигнорировать любые закэшированные данные, вызовите org.hibernate.Query.setCacheMode(CacheMode.REFRESH). В паре с регионом, определенным для запроса, Hibernate выборочно обновит результаты, закэшированные в данном регионе. Это более эффективно, нежели групповое удаление записей (bulk eviction) из региона c помощью org.hibernate.SessionFactory.evictQueries().
Hibernate совместим с некоторыми провайдерами кэша второго уровня. Ни один из провайдеров не поддерживает абсолютно все возможные стратегии кэширования, определенные в Hibernate. Секция 6.2.3, “Провайдеры кэша второго уровня для Hibernate” содержит список провайдеров, вместе с их интерфейсами и поддерживаемыми стратегиями кэширования. Для определений стратегий кэширования, см. Секцию 6.2.2, “Стратегии кэширования”.
Вы можете конфигурировать ваши кэш-провайдеры, используя аннотации или файлы маппинга. Сущности, по-умолчанию, не являются частью кэша второго уровня, и их использование не рекомендуется. Если вам все равно необходимо использовать сущности, установите элемент shared-cache-mode в persistence.xml, или используйте свойство javax.persistence.sharedCache.mode в вашей конфигурации. Используйте одно из значений Таблицы 6.1, “Возможные значения для Shared Cache Mode”.
Таблица 6.1. Возможные значения для Shared Cache Mode
Глобальная concurrency-стратегия устанавливается с помощью свойства hibernate.cache.default_cache_concurrency_strategy. См. возможные значения в секции 6.2.2, “Стратегии кэширования”.
Пример 6.2. Конфигурация кэш-провайдеров с использованием аннотаций.
Вы можете кэшировать содержимое коллекций или идентификаторов, если коллекция содержит другие сущности. Используйте аннотацию @Cache на свойстве коллекции.
@Cache содержит несколько атрибутов.
Атрибуты аннотации @Cache:
Пример 6.3. Конфигурация кэш-провайдеров с использованием файлов маппинга.
Как и в Примере 6.2, “Конфигурация кэш-провайдеров с использованием аннотаций”, вы можете указывать атрибуты в файлах маппинга. Есть несколько специфических различий в синтаксисе атрибутов в файлах маппинга.
Вместо cache, вы можете использовать элементы class-cache, collection-cache в hibernate.cfg.xml.
Действия, добавляющие записи во внутренний кэш сессии:
Синхронизация или удаление закэшированной записи. Состояние объекта синхронизируется с БД, когда вы вызываете метод flush(). Чтобы избежать синхронизации, вы можете удалить объект и его коллекции из кэша первого уровня с помощью метода evict(). Для удаления всех записей из кэша сессии, используйте метод Session.clear().
Пример 6.4. Удаление записи из кэша первого уровня
Как определить, принадлежит ли сущность кэшу сессии. Объект Session предоставляет метод contains() для определения принадлежности объекта к кэшу сессии.
Пример 6.5 Удаление из кэша второго уровня
Вы можете удалить закэшированное состояние сущности, всего класса, коллекции, или все роли коллекции, используя методы SessionFactory
После разрешения статистики, вы можете просматривать содержимое кэша второго уровня или региона кэширования.
Процедура 6.2. Разрешение статистики
Пример 6.6. Просмотр кэша второго уровня через Statistics API
Перевод статьи актуален для версии Hibernate 4.2.19.Final
Предыдущая глава — Документация разработчика Hibernate – Глава V. Блокировки
Что собой представляют кэш первого и второго уровня в Hibernate, показано на следующий диаграмме (прим. автора).
6.1. Кэш запросов
Если у вас есть запросы, выполняющиеся снова и снова, с одними и теми же параметрами, кэширование запросов предоставит выигрыш в производительности.
Кэширование вводит дополнительные накладные расходы в области выполнения транзакций. К примеру, если вы кэшируете результаты запроса по отношению к какому-либо объекту, Hibernate необходимо отслеживать, были ли закоммичены какие-либо изменения по объекту, и в соответствии с этим, аннулировать записи в кэше. В дополнение, плюсы от кэширования запросов ограничены, и очень зависят от шаблонов использования вашего приложения. По этим причинам, Hibernate по-умолчанию выключает кэширование запросов.
Процедура 6.1. Разрешение кэширования запросов
- Выставьте свойство hibernate.cache.use_query_cache в true.
Эта настройка создаст два новых региона кэширования:
- org.hibernate.cache.internal.StandardQueryCache хранит результаты кэшированных запросов.
- org.hibernate.cache.spi.UpdateTimestampsCache хранит временные метки недавних апдейтов в запрашиваемые таблицы. Эти временные метки валидируют результаты, берущиеся из кэша запроса (т.е. через них проверяется актуальность объектов, — прим.перев.)
- Настройте таймаут региона кэширования
Если вы конфигурируете таймауты или окончание срока в вашей реализации кэша, выставьте таймаут нижележащего кэш-региона для UpdateTimestampsCache на большее значение, чем таймауты любого из кэшей запросов. Вполне возможно, и рекомендуется, выставлять бесконечный таймаут истечения у региона UpdateTimestampsCache. Если быть более конкретным, LRU-политика кэширования (Least Recently Used) не считается подходящей.
- Разрешите кэширование результатов для конкретных запросов
Так как большая часть запросов не выигрывает от кэширования, вам нужно разрешить кэширование только для индивидуальных запросов, даже после повсеместного разрешения кэширования. Для того, чтобы разрешить кэширование для определенного запроса, вызовите org.hibernate.Query.setCacheable(true). Вызов позволит запросу ”заглянуть” в кэш перед выполнением, или положить туда результаты после выполнения.
Кэш запросов не кэширует состояние актуальных сущностей в кэше. Он кэширует значения идентификаторов и результаты типов. Таким образом, всегда используете кэш запросов в паре с кэшем второго уровня для тех сущностей, которые должны кэшироваться как часть кэша запросов.
6.1.1. Регионы кэша запросов
Для лучшего контроля за политиками истечения актуальности у кэшей запросов, укажите именованный регион кэширования для определенного запроса, вызвав Query.setCacheRegion().
Пример 6.1. Метод setCacheRegion
List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
.setEntity("blogger", blogger)
.setMaxResults(15)
.setCacheable(true)
.setCacheRegion("frontpages")
.list();
Чтобы заставить кэш запросов обновить один из его регионов, и проигнорировать любые закэшированные данные, вызовите org.hibernate.Query.setCacheMode(CacheMode.REFRESH). В паре с регионом, определенным для запроса, Hibernate выборочно обновит результаты, закэшированные в данном регионе. Это более эффективно, нежели групповое удаление записей (bulk eviction) из региона c помощью org.hibernate.SessionFactory.evictQueries().
6.2. Провайдеры кэша второго уровня
Hibernate совместим с некоторыми провайдерами кэша второго уровня. Ни один из провайдеров не поддерживает абсолютно все возможные стратегии кэширования, определенные в Hibernate. Секция 6.2.3, “Провайдеры кэша второго уровня для Hibernate” содержит список провайдеров, вместе с их интерфейсами и поддерживаемыми стратегиями кэширования. Для определений стратегий кэширования, см. Секцию 6.2.2, “Стратегии кэширования”.
6.2.1. Конфигурация пользовательских кэш-провайдеров
Вы можете конфигурировать ваши кэш-провайдеры, используя аннотации или файлы маппинга. Сущности, по-умолчанию, не являются частью кэша второго уровня, и их использование не рекомендуется. Если вам все равно необходимо использовать сущности, установите элемент shared-cache-mode в persistence.xml, или используйте свойство javax.persistence.sharedCache.mode в вашей конфигурации. Используйте одно из значений Таблицы 6.1, “Возможные значения для Shared Cache Mode”.
Таблица 6.1. Возможные значения для Shared Cache Mode
Значение | Описание |
---|---|
ENABLE_SELECTIVE | Сущности не будут кэшироваться, до тех пор, пока вы явно не пометите их как кэшируемые. Это значение рекомендуется и используется по-умолчанию. |
DISABLE_SELECTIVE | Сущности будут кэшироваться, до тех пор, пока вы явно не отмените кэширование на них. |
ALL | Все сущности будут кэшироваться, в независимости от того, пометите ли вы их как некэшируемые. |
NONE | Ни одна сущность не будет кэшироваться, даже если вы пометите их как кэшируемые. Эта опция отменяет работу кэша второго уровня. |
Глобальная concurrency-стратегия устанавливается с помощью свойства hibernate.cache.default_cache_concurrency_strategy. См. возможные значения в секции 6.2.2, “Стратегии кэширования”.
Важно
Когда это возможно, определяйте concurrency-стратегию кэширования только для определенной сущности, но не глобально. Используйте аннотацию @org.hibernate.annotations.Cache.
Пример 6.2. Конфигурация кэш-провайдеров с использованием аннотаций.
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }
Вы можете кэшировать содержимое коллекций или идентификаторов, если коллекция содержит другие сущности. Используйте аннотацию @Cache на свойстве коллекции.
@Cache содержит несколько атрибутов.
Атрибуты аннотации @Cache:
Имя | Описание |
---|---|
usage | Заданная concurrency-стратегия кэша, которая может быть:
|
region | Регион кэширования. Этот атрибут опционален, и по-умолчанию совпадает с полным именем класса, или ролевым именем коллекции (qualified role name of the collection). |
include | Включать или нет все свойства. Опционально, и может принимать два возможных значения.
|
Пример 6.3. Конфигурация кэш-провайдеров с использованием файлов маппинга.
<cache
usage="transactional"
region="RegionName"
include="all"
/>
Как и в Примере 6.2, “Конфигурация кэш-провайдеров с использованием аннотаций”, вы можете указывать атрибуты в файлах маппинга. Есть несколько специфических различий в синтаксисе атрибутов в файлах маппинга.
Имя | Описание |
---|---|
usage | Стратегия кэширования. Этот атрибут обязателен, и может принимать любое из следующих значений:
|
region | Имя региона кэша второго уровня. По-умолчанию совпадает полным именем класса или ролевым именем коллекции. |
include | Могут ли свойства сущности, указанные с lazy=true, кэшироваться, когда разрешена ”ленивая” выборка на уровне атрибутов. По-умолчанию all и может быть также non-lazy |
Вместо cache, вы можете использовать элементы class-cache, collection-cache в hibernate.cfg.xml.
6.2.2. Стратегии кэширования
- read-only
Read-only кэш хорош для данных, которые читаются, но не изменяются. Простой, хорошо работающий подход, безопасный к тому же в кластеризованном окружении. - nonstrict read-write
Некоторым приложениям необходимо лишь иногда читать данные. Это тот случай, когда две транзакции врядли одновременно обновят одну и ту же сущность. В таком случае, вам не нужно ограничивать изоляцию транзакций, и nonstrict-read-write кэш весьма подходящ. Если кэш используется в JTA-окружении, вы должны указать hibernate.transaction.manager_lookup_class. В других окружениях, убедитесь что транзакция завершена, перед тем как вызвать Session.close() или Session.disconnect().
- read-write
Read-write кэш подходит для приложения, где данные обновляются регулярно. Не используйте read-write стратегию, если вам нужна сериализуемая изоляция транзакций. В JTA-окружении, укажите стратегию для получения JTA TransactionManager, выставив свойство hibernate.transaction.manager_lookup_class. В не-JTA окружениях, убедитесь, что транзакция завершена, перед тем как вызвать Session.close() или Session.disconnect().
ВажноДля использования read-write стратегии в кластеризованном окружении, нижележащая реализация кэша должна поддерживать блокировки. Встроенные кэш-провайдеры не поддерживают блокировки.
- transactional
Transactional стратегия кэширования предоставляет поддержку для транзакционных кэш-провайдеров, таких как JBoss TreeCache. Использовать такой кэш вы можете только в JTA-окружении, и для начала вам нужно будет указать hibernate.transaction.manager_lookup_class.
6.2.3. Провайдеры Hibernate для кэша второго уровня
Кэш | Поддерживаемые стратегии |
---|---|
HashTable (только для тестов) |
|
EHCache |
|
Infinispan |
|
6.3. Управление кэшем
6.3.1. Добавление/извлечение записей из кэша
Действия, добавляющие записи во внутренний кэш сессии:
Сохранение или апдейт сущности | Извлечение сущности |
---|---|
|
|
Синхронизация или удаление закэшированной записи. Состояние объекта синхронизируется с БД, когда вы вызываете метод flush(). Чтобы избежать синхронизации, вы можете удалить объект и его коллекции из кэша первого уровня с помощью метода evict(). Для удаления всех записей из кэша сессии, используйте метод Session.clear().
Пример 6.4. Удаление записи из кэша первого уровня
ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
while ( cats.next() ) {
Cat cat = (Cat) cats.get(0);
doSomethingWithACat(cat);
sess.evict(cat);
}
Как определить, принадлежит ли сущность кэшу сессии. Объект Session предоставляет метод contains() для определения принадлежности объекта к кэшу сессии.
Пример 6.5 Удаление из кэша второго уровня
Вы можете удалить закэшированное состояние сущности, всего класса, коллекции, или все роли коллекции, используя методы SessionFactory
sessionFactory.getCache().containsEntity(Cat.class, catId); // is this particular Cat currently in the cache
sessionFactory.getCache().evictEntity(Cat.class, catId); // evict a particular Cat
sessionFactory.getCache().evictEntityRegion(Cat.class); // evict all Cats
sessionFactory.getCache().evictEntityRegions(); // evict all entity data
sessionFactory.getCache().containsCollection("Cat.kittens", catId); // is this particular collection currently in the cache
sessionFactory.getCache().evictCollection("Cat.kittens", catId); // evict a particular collection of kittens
sessionFactory.getCache().evictCollectionRegion("Cat.kittens"); // evict all kitten collections
sessionFactory.getCache().evictCollectionRegions(); // evict all collection data
6.3.1.2. Просмотр содержимого кэша второго уровня и кэшей запросов
После разрешения статистики, вы можете просматривать содержимое кэша второго уровня или региона кэширования.
Процедура 6.2. Разрешение статистики
- Выставьте hibernate.generate_statistics в true.
- Необязательно – выставьте hibernate.cache.use_structured_entries в true, чтобы Hibernate мог хранить записи в понятном пользователю формате.
Пример 6.6. Просмотр кэша второго уровня через Statistics API
Map cacheEntries = sessionFactory.getStatistics()
.getSecondLevelCacheStatistics(regionName)
.getEntries();
ivanra
После 6.3.1 текст повторяется. Похоже, сбой в матрице
otvorot2008
Да, поправил. Спасибо:)