senior
Что такое Query Cache?
Query Cache — кэш результатов JPQL/HQL-запросов. Хранит не данные сущностей, а список ID, возвращённых запросом с определёнными параметрами.
Как работает
Пример
Ключ кэша: запрос + параметры
Значение: список ID сущностей
При чтении: Query Cache → получить ID → L2 Cache → получить данные по ID → (если нет в L2 → БД)
Настройка
Пример
spring.jpa.properties.hibernate.cache.use_query_cache=true
Пример
// JPQL с кэшированием
List<User> users = entityManager.createQuery(
"SELECT u FROM User u WHERE u.status = :status", User.class)
.setParameter("status", UserStatus.ACTIVE)
.setHint("org.hibernate.cacheable", true)
.getResultList();
// Spring Data JPA
@QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true"))
@Query("SELECT u FROM User u WHERE u.status = :status")
List<User> findByStatus(@Param("status") UserStatus status);
Важное
- Query Cache хранит список ID, а не данные — работает в связке с L2 Cache
- Query Cache инвалидируется при любом изменении таблицы, участвующей в запросе
- Эффективен только для запросов, которые выполняются часто с одинаковыми параметрами
- Без L2 Cache — Query Cache бесполезен (ID есть, но данные придётся загружать из БД)
Частые ошибки
- Включать Query Cache без L2 Cache — получив список ID из Query Cache, Hibernate пойдёт за каждой сущностью в БД (хуже, чем без кэша)
- Кэшировать запросы к часто обновляемым таблицам — любой UPDATE/INSERT/DELETE инвалидирует весь Query Cache для этой таблицы
- Кэшировать все запросы подряд — Query Cache полезен только для стабильных данных с повторяющимися параметрами
Как используется в 2026
- Query Cache — нишевый инструмент, используется реже L2 Cache
- Для большинства задач кэширования на уровне запросов — Spring Cache + Redis
- Query Cache оправдан для тяжёлых аналитических запросов к неизменяемым данным
На собеседовании: покажите, что понимаете связку Query Cache + L2 Cache. Без L2 Cache включать Query Cache бессмысленно и даже вредно. Подчеркните, что Query Cache инвалидируется при любом изменении таблицы — это делает его бесполезным для часто обновляемых данных.