Як налаштувати кеш другого рівня
Налаштування кешу другого рівня включає вибір провайдера, конфігурацію Hibernate, налаштування регіонів кешу та визначення стратегій кешування для кожної сутності.
Огляд
Налаштування кешу другого рівня включає вибір провайдера, конфігурацію Hibernate, налаштування регіонів кешу та визначення стратегій кешування для кожної сутності.
🟢 Junior Level
Базове налаштування
Для налаштування L2 cache потрібно виконати 3 кроки:
- Увімкнути кеш в конфігурації
- Обрати провайдера (Ehcache, Hazelcast, Redis)
- Позначити сутності анотацією
@Cacheable
# application.yml
spring:
jpa:
properties:
hibernate:
cache:
use_second_level_cache: true
region:
factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
javax.persistence.sharedCache.mode: ENABLE_SELECTIVE
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User {
@Id
private Long id;
private String name;
}
Режими кешування
# Всі сутності кешуються за замовчуванням
javax.persistence.sharedCache.mode: ALL
# Тільки позначені @Cacheable (рекомендується)
javax.persistence.sharedCache.mode: ENABLE_SELECTIVE
# Всі крім позначених @Cacheable(false)
javax.persistence.sharedCache.mode: DISABLE_SELECTIVE
# Жодні (кеш вимкнений)
javax.persistence.sharedCache.mode: NONE
🟡 Middle Level
Коли НЕ використовувати L2 cache
- Write-heavy workload — постійна інвалідація кешу дорожча ніж SELECT з БД
- Високо нормалізовані дані з частими JOIN — кеш неефективний
- Багатовузловий кластер з частими оновленнями — invalidation traffic перевищує користь
Налаштування Ehcache
<!-- ehcache.xml в src/main/resources -->
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'>
<cache alias="com.example.User">
<heap unit="entries">1000</heap>
<offheap unit="MB">50</offheap>
<expiry>
<ttl unit="minutes">30</ttl>
</expiry>
</cache>
<cache alias="com.example.Country">
<heap unit="entries">500</heap>
<expiry>
<ttl unit="hours">24</ttl>
</expiry>
</cache>
</config>
Управління кешем програмно
Cache cache = entityManager.getEntityManagerFactory().getCache();
// Evict конкретну сутність
cache.evict(User.class, userId);
// Evict всі сутності типу
cache.evict(User.class);
// Evict все
cache.evictAll();
Колекції в кеші
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User {
@OneToMany(mappedBy = "user")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<Order> orders; // кешування колекції
}
Типові помилки
// ❌ Немає TTL — кеш росте нескінченно
// Рішення: завжди задавайте TTL в конфігурації провайдера
// ❌ Кеш для всіх сутностей
// Рішення: кешуйте тільки часто читані, рідко змінювані
// ❌ Неправильна стратегія
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Order { } // ❌ Orders часто змінюються
🔴 Senior Level
Кластерний кеш
# Hazelcast для кластера
spring:
jpa:
properties:
hibernate:
cache:
region:
factory_class: com.hazelcast.hibernate.HazelcastCacheRegionFactory
Проблеми кластерного кешу:
- Eventual consistency (не strong) — дані в різних вузлах кластера стануть однаковими не миттєво, а через деякий час.
- Network latency при реплікації
- Конфлікти при одночасному оновленні
- Необхідність стратегії інвалідації кешу
Налаштування регіонів
@Entity
@Cacheable
@org.hibernate.annotations.Cache(
usage = CacheConcurrencyStrategy.READ_WRITE,
region = "userCache" // ім'я регіону
)
public class User { }
Моніторинг в production
Statistics stats = entityManagerFactory
.unwrap(SessionFactory.class)
.getStatistics();
long hitCount = stats.getSecondLevelCacheHitCount();
long missCount = stats.getSecondLevelCacheMissCount();
double hitRatio = (double) hitCount / (hitCount + missCount);
// hitRatio > 0.8 зазвичай добре для read-heavy навантаження
Query Cache
spring:
jpa:
properties:
hibernate:
cache:
use_query_cache: true
// Важливо: query cache зберігає тільки ID сутностей
// Самі сутності беруться з L2 cache
Best Practices
✅ TTL для кожного region
✅ Heap limit для запобігання memory leak
✅ Кластерний кеш для multi-node додатків
✅ Моніторинг hit ratio
✅ ENABLE_SELECTIVE mode
✅ READ_ONLY для довідників
❌ Без TTL та лімітів
❌ Кеш для даних що часто змінюються
❌ Без моніторингу hit ratio
❌ Query cache без L2 cache
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- 3 кроки налаштування: увімкнути кеш, обрати провайдера, позначити сутності @Cacheable
- Режими: ENABLE_SELECTIVE (рекомендується), ALL, DISABLE_SELECTIVE, NONE
- Стратегії кешування: READ_ONLY для довідників, READ_WRITE для змінюваних даних
- Кластерний кеш: Hazelcast/Redis, eventual consistency, network overhead
- Query cache марний без L2 cache — зберігає тільки ID сутностей
Пов’язані теми:
- [[10. Що таке кеш другого рівня і коли його використовувати]]
- [[9. Що таке кеш першого рівня в Hibernate]]
- [[12. Що таке dirty checking в Hibernate]]
- [[1. Що таке проблема N+1 і як її вирішити]]