Какие уровни кэширования существуют в Hibernate?

«Какие уровни кэширования существуют в Hibernate?» — вопрос из категории Hibernate, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Hibernate предоставляет многоуровневую систему кэширования для минимизации обращений к базе данных.

1. Кэш первого уровня (L1, Session Cache)

  • Включен по умолчанию, привязан к объекту Session (или EntityManager).
  • Обеспечивает гарантию уникальности экземпляра сущности в рамках сессии.
  • Жизненный цикл равен жизненному циклу сессии.
Session session = sessionFactory.openSession();
// Первый вызов -> запрос к БД, результат кладется в L1
User u1 = session.get(User.class, 1L);
// Второй вызов -> данные берутся из L1 кэша
User u2 = session.get(User.class, 1L);
assert u1 == u2; // true
session.close(); // Кэш очищается

2. Кэш второго уровня (L2, Second-Level Cache)

  • Разделяемый кэш между разными сессиями.
  • Требует явной настройки и внешнего провайдера (Ehcache, Infinispan, Hazelcast).
  • Сущность должна быть помечена как кэшируемая.
@Entity
@Cacheable // JPA аннотация
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) // Стратегия Hibernate
public class Product { ... }

3. Кэш запросов (Query Cache)

  • Кэширует результаты HQL/Criteria/JPA Query вместе с идентификаторами сущностей.
  • Для работы требует включенного L2 кэша.
  • Настраивается в конфигурации Hibernate и указывается для конкретного запроса.
Query query = session.createQuery("from User where active = true");
query.setCacheable(true); // Включение кэширования для этого запроса
List<User> users = query.list();

Применение: Кэширование наиболее эффективно для данных, которые часто читаются и редко изменяются (справочники, конфигурации).