Как работает кэширование в Hibernate?
HibernateJavaкэшированиефреймворки
Что проверяют
Различаете ли вы три независимых механизма и понимаете ли, что кэш второго уровня решает другую задачу, чем N+1, и требует продуманной стратегии согласованности.
Как отвечать
- Кэш первого уровня это сам контекст персистентности (
Session,EntityManager). Он всегда включён, отключить его нельзя, живёт в границах сессии и даёт identity map: две загрузки одной строки в одной сессии вернут один и тот же объект. В пакетной обработке контекст растёт, поэтому нужны периодическиеflush()иclear(). - Поиск в первом уровне идёт только по идентификатору (
find,getReference, ленивая навигация). Запрос на JPQL или Criteria всё равно уйдёт в базу, но перед этим сработает flush, чтобы запрос увидел незакоммиченные изменения. - Кэш второго уровня общий на
SessionFactoryи живёт между сессиями. Включается явно, требует провайдера (сейчас это JCache с Ehcache 3, Infinispan или Redis; Ehcache 2 устарел) и аннотации@Cacheсо стратегией:READ_ONLYдля справочников,READ_WRITEс мягкими блокировками, режеNONSTRICT_READ_WRITE. - Хранит он не объекты, а разобранное состояние сущности по ключу-идентификатору.
- Кэш запросов выключен по умолчанию и хранит только списки идентификаторов и скалярные результаты. Без включённого кэша сущностей он почти бесполезен: за строками всё равно придётся идти в базу. Любая запись в участвующие таблицы инвалидирует область, поэтому на часто меняющихся данных промахов больше, чем пользы.
- Главное ограничение: правки мимо Hibernate (нативный SQL, соседний сервис, миграция) кэш не видит, а в кластере нужен провайдер с инвалидацией между узлами.
Где спотыкаются
Ждут от второго уровня решения проблемы N+1. Она лечится join fetch, entity graph и @BatchSize, а кэш лишь маскирует её при повторных обращениях.
Думают, что кэш запросов хранит строки. Он хранит идентификаторы, и без кэша сущностей каждое попадание превращается в пачку запросов.
Считают первый уровень настраиваемым кэшем с временем жизни. Это контекст персистентности, его срок жизни равен сроку жизни сессии.