Прежде всего, давайте поговорим о кэше уровня процесса (или кэше 2-го уровня, как его называют в Hibernate). Чтобы это заработало, вы должны
- настроить кеш провайдера
- сообщает hibernate, какие объекты следует кэшировать (прямо в файле hbm.xml, если вы используете этот тип отображения).
Вы сообщаете провайдеру кэша, сколько объектов он должен хранить и когда / почему они должны быть признаны недействительными. Допустим, у вас есть сущности Book и Author, каждый раз, когда вы получаете их из БД, из БД выбираются только те, которые не находятся в кеше. Это значительно повышает производительность. Это полезно, когда:
- Вы пишете в базу данных только через Hibernate (потому что ей нужен способ узнать, когда нужно изменить или сделать недействительными сущности в кеше)
- Вы часто читаете объекты
- У вас есть один узел, и у вас нет репликации. В противном случае вам нужно будет реплицировать сам кеш (использовать распределенные кеши, такие как JGroups), что увеличивает сложность и не так хорошо масштабируется, как приложения без совместного использования.
Так когда же работает кеш?
- Когда вы
session.get()
или session.load()
объект, который был ранее выбран и находится в кэше. Кэш-память - это хранилище, где ID является ключом, а свойства - значениями. Поэтому, только когда есть возможность поиска по идентификатору, вы можете исключить попадание в БД.
- Когда ваши ассоциации загружаются лениво (или загружаются с помощью селекторов вместо объединений)
Но это не работает, когда:
- Если вы не выбираете по ID. Опять же - кэш 2-го уровня хранит карту идентификаторов сущностей с другими свойствами (на самом деле он хранит не объекты, а сами данные), поэтому, если ваш поиск выглядит следующим образом:
from Authors where name = :name
, вы не нажмете на кеш.
- Когда вы используете HQL (даже если вы используете
where id = ?
).
- Если в вашем отображении вы установили
fetch="join"
, это означает, что для загрузки ассоциаций объединения будут использоваться везде вместо отдельных операторов выбора. Кэш уровня процесса работает на дочерних объектах, только если используется fetch="select"
.
- Даже если у вас есть
fetch="select"
, но в HQL вы используете объединения для выбора ассоциаций - эти объединения будут выпущены сразу, и они будут перезаписывать все, что вы указали в hbm.xml или аннотациях.
Теперь о Query Cache. Следует отметить, что это не отдельный кеш, а дополнение к кешу уровня процесса. Допустим, у вас есть организация Country. Это статично, поэтому вы знаете, что каждый раз, когда вы говорите from Country
, будет один и тот же набор результатов. Это идеальный кандидат для кеша запросов, он будет хранить список ID сам по себе, и когда вы в следующий раз выберете все страны, он вернет этот список в кеш уровня процесса, а последний, в свою очередь, будет возвращать объекты для каждого идентификатора, так как эти объекты уже хранятся в кэше 2-го уровня.
Кэш запросов становится недействительным каждый раз, когда что-либо связанное с сущностью изменяется. Допустим, вы настроили from Authors
для помещения в кеш запросов. Это не будет эффективно, поскольку Автор часто меняется. Поэтому вы должны использовать Query Cache только для более или менее статических данных.