Когда и как использовать кеш второго уровня гибернации?

91

Мне трудно понять, когда спящий режим попадает во второй уровень кеша, а когда он делает недействительным кеш.

Вот что я сейчас понимаю:

  • Кэш второго уровня хранит объекты между сеансами, область действия - SessionFactory
  • Вы должны указать, какие объекты кэшировать, по умолчанию никакие объекты не будут кэшироваться.
  • Кэш запросов хранит результаты запросов в кеше.

Я не понимаю

  • Когда спящий режим попадает в этот кеш?
  • Допустим, я установил кеш второго уровня, но не кеширование запросов. Я хочу кэшировать своих клиентов, их 50000. Как я могу получить клиентов из кеша?
  • Я предполагаю, что могу получить их по идентификатору из кеша. Это было бы легко, но кешировать не стоит. Но что, если я хочу произвести какие-то расчеты со всеми своими клиентами. Допустим, я хочу показать список клиентов, тогда как мне получить к ним доступ?
  • Как мне получить всех своих клиентов, если кеширование запросов отключено?
  • Что будет, если кто-то обновит одного из клиентов?
    • Будет ли этот клиент признан недействительным в кеше или все клиенты станут недействительными?

Или я считаю кеширование совершенно неправильным? Что было бы более подходящим использованием кеша второго уровня в этом случае? В документации по гибернации вообще не понятно, как кеш работает на самом деле. Есть только инструкции по его настройке.

Обновление: Итак, я понял, что кеш второго уровня (без кеша запросов) был бы хорош для загрузки данных по идентификатору. Например, у меня есть пользовательский объект, разрешения на который я хочу проверять в каждом запросе в веб-приложении. Будет ли это хорошим случаем для уменьшения доступа к базе данных путем кэширования пользователя в кеш второго уровня? Как будто я сохраняю идентификатор пользователя в сеансе или где угодно, и когда мне нужно проверить разрешения, я загружал пользователя по его идентификатору и проверял разрешения.

Palto
источник

Ответы:

102

Прежде всего, давайте поговорим о кеш-памяти уровня процесса (или кеш-памяти 2-го уровня, как его называют в Hibernate). Чтобы это работало, вы должны

  1. настроить поставщик кеша
  2. сообщить спящему режиму, какие объекты кэшировать (прямо в файле hbm.xml, если вы используете такой тип сопоставления).

Вы сообщаете поставщику кеша, сколько объектов он должен хранить и когда / почему они должны быть признаны недействительными. Итак, допустим, у вас есть сущности Book и Author, каждый раз, когда вы получаете их из БД, только те, которые не находятся в кеше, будут выбираться из фактической БД. Это значительно увеличивает производительность. Это полезно, когда:

  • Вы пишете в базу данных только через Hibernate (потому что ему нужен способ узнать, когда изменять или аннулировать объекты в кеше)
  • Вы часто читаете предметы
  • У вас есть единственный узел, и у вас нет репликации. В противном случае вам нужно будет реплицировать сам кеш (использовать распределенные кеши, такие как JGroups), что добавляет больше сложности и не масштабируется так хорошо, как приложения без совместного использования.

Итак, когда работает кеш?

  • Когда вы session.get()или session.load()объект, который был выбран ранее и находится в кеше. Кэш - это хранилище, в котором идентификатор является ключом, а свойства - значениями. Таким образом, только когда есть возможность поиска по идентификатору, вы можете исключить попадание в БД.
  • Когда ваши ассоциации загружаются лениво (или загружаются с нетерпением с помощью выборок вместо объединений)

Но не работает, когда:

  • Если вы не выбираете по ID. Опять же - кеш 2-го уровня хранит карту идентификаторов сущностей с другими свойствами (на самом деле он хранит не объекты, а сами данные), поэтому, если ваш поиск выглядит так:, from Authors where name = :nameто вы не попадаете в кеш.
  • Когда вы используете HQL (даже если используете where id = ?).
  • Если в вашем сопоставлении вы установили fetch="join", это означает, что для загрузки ассоциаций везде будут использоваться объединения вместо отдельных операторов выбора. Кэш уровня процесса работает с дочерними объектами, только если fetch="select"он используется.
  • Даже если у вас есть, fetch="select"но тогда в HQL вы используете объединения для выбора ассоциаций - эти объединения будут выданы сразу, и они перезапишут все, что вы указали в hbm.xml или аннотациях.

Теперь о кэше запросов. Обратите внимание, что это не отдельный кеш, это дополнение к кешу уровня процесса. Допустим, у вас есть организация Country. Это статично, поэтому вы знаете, что каждый раз, когда вы говорите, будет один и тот же набор результатов from Country. Это идеальный кандидат для кеширования запросов, он будет хранить в себе список идентификаторов , и когда вы в следующий раз выберете все страны, он вернет этот список в кеш уровня процесса, а последний, в свою очередь, вернет объекты для каждого идентификатора поскольку эти объекты хранятся уже в кеше 2-го уровня. Кэш запросов становится недействительным каждый раз, когда изменяется что-либо, связанное с сущностью. Предположим, вы настроили from Authorsразмещение в кэше запросов. Это не сработает, поскольку Автор часто меняется.

Станислав Башкирцев
источник
Требуется ли для запроса «from Author a fetch join a.books» кеш запросов для извлечения авторов из кеша?
palto
1
Нет, кеш запросов предназначен только для статических данных и хранит только идентификаторы. Авторы будут взяты из кеша 2-го уровня.
Станислав Башкирцев
@ctapobep: неправда, что ты говоришь! "from Author a fetch join a.books" отлично работает, если полевые книги сущности Author аннотированы (получить EAGER) ... я думаю, слишком поздно
Билал BBB
Такой отличный ответ! Я буду помнить это все время! : d
Мохаммадреза Хатами
после включения «кеша запросов» извлекает ли он данные из кеша, если вы выбираете другое свойство, кроме id?
Арун
43
  • кеш 2-го уровня - это хранилище ключей и значений. Это работает, только если вы получаете свои объекты по идентификатору
  • кеш 2-го уровня становится недействительным / обновляется для каждой сущности, когда сущность обновляется / удаляется через спящий режим. Он не считается недействительным, если база данных обновляется другим способом.
  • для запросов (например, список клиентов) используйте кеш запросов.

На самом деле полезно иметь распределенный кеш по ключу - это то, что такое memcached, и он поддерживает facebook, twitter и многие другие. Но если у вас нет поисков по идентификатору, то это будет не очень полезно.

Божо
источник
Кеш запросов (работает с Projection, ResultTransformers для шаблонов DTO) и становится недействительным, если вы обновляете Entity, который использовался в кешированном запросе. Как вы сказали, кеш 2-го уровня работает только для тех запросов, в которых вы получаете объект по идентификатору (не работает для ограничений критериев) или критериев с проекциями (выберите только некоторые свойства). Кстати, лучший (возобновленный) ответ на вопрос «как работает кеш спящего режима».
ics_mauricio
12

Поздно к вечеринке, но хотел систематически ответить на этот вопрос, который задают многие разработчики.

Я отвечу на ваши вопросы один за другим.

В. Когда спящий режим попадает в этот кеш?

A. Кэш первого уровня связан с объектом сеанса . Второй уровень кэша связан с объектом Factory Session . Если объект не найден на первом, то проверяется второй уровень.

В. Допустим, я установил кеш второго уровня, но не кеширование запросов. Я хочу кэшировать своих клиентов, их 50000. Как я могу получить клиентов из кеша?

A. Вы ответили на этот вопрос в своем обновлении. Кроме того, в кэше запросов хранится только список идентификаторов объекта, а эти объекты со своими идентификаторами хранятся в том же кэше второго уровня. Поэтому, если вы включите кеширование запросов, вы будете использовать тот же ресурс. Аккуратно, правда?

В. Я предполагаю, что могу получить их по идентификатору из кеша. Это было бы легко, но кешировать не стоит. Но что, если я хочу произвести какие-то расчеты со всеми своими клиентами. Допустим, я хочу показать список клиентов, тогда как мне получить к ним доступ?

А. Ответил выше.

В. Как мне получить всех своих клиентов, если кеширование запросов отключено?

А. Ответил выше.

В. Что произойдет, если кто-то обновит одного из клиентов? Будет ли этот клиент признан недействительным в кеше или все клиенты станут недействительными?

A. Hibernate понятия не имеет, но вы можете использовать другие сторонние IMDG / распределенные кеши, которые будут реализованы как кеш второго уровня спящего режима и сделать их недействительными. например, TayzGrid - один из таких продуктов, и я думаю, что их гораздо больше.

Басит Анвер
источник
0

Кэш второго уровня Hibernate немного сложно понять и реализовать. Вот что мы можем сказать по вашим вопросам:

Когда Hibernate попадает в этот кеш?

Как вы предполагаете, кэш L2 Hibernate (если он включен; он не включен по умолчанию) запрашивается только после кеша L1. Это кэш «ключ-значение», данные которого сохраняются в течение нескольких сеансов.

Допустим, я установил кеш второго уровня, но не кеширование запросов. Я хочу кэшировать своих клиентов, их 50000. Как я могу получить клиентов из кеша?

Кэширование запросов было бы лучше всего для этого варианта использования, поскольку данные клиентов статичны и извлекаются из реляционной базы данных.

Что будет, если кто-то обновит одного из клиентов? Будет ли этот клиент признан недействительным в кеше или все клиенты станут недействительными?

Это зависит от конкретной стратегии кеширования Hibernate, которую вы используете. На самом деле Hibernate имеет четыре разных стратегии кеширования:

READ_ONLY : объекты не меняются ни разу внутри кеша.

NONSTRICT_READ_WRITE : объекты изменяются (в конечном итоге) после обновления соответствующей записи в базе данных; это гарантирует конечную согласованность.

READ_WRITE : объекты изменяются (сразу) после обновления соответствующей записи в базе данных; это гарантирует прочную консистенцию за счет использования «мягких» замков.

TRANSACTIONAL : объекты меняются с помощью распределенных транзакций XA, обеспечивая целостность данных; это гарантирует либо полный успех, либо откат всех изменений. Однако во всех четырех случаях обновление одной записи в базе данных не приведет к аннулированию всего списка клиентов в кэше. Hibernate немного умнее этого :)

Чтобы узнать больше о том, как кэширование L2 работает в Hibernate, вы можете прочитать статью «Что такое кеш L2 Hibernate» или подробную статью Кэширование в Hibernate с помощью Redis.

Никита Кокшаров
источник