Configuring L2 + Query Cache — Providers, Regions, and Tuning
Fast recall
Quick revision
Core answer
application.yml, choose a JCache (JSR-107) provider — Caffeine for single-instance, Hazelcast or Infinispan for clusters, Ehcache 3 for legacy parity — and annotate cacheable entities with @org.hibernate.annotations.Cache(usage = READ_WRITE, region = "..."). Configure per-region size, TTL, and eviction in the provider config (e.g., caffeine.spec), opt queries into the cache with `HINT_CACHEABLE`, and turn on `generate_statistics` plus Actuator. Provider choice depends on topology (single JVM vs cluster), invalidation requirements (broadcast vs local), and operational maturity.Whether the candidate can move from theory to a working configuration: providers, regions, TTLs, query hints, and observability
Adding `@Cacheable` (JPA) and assuming it works — without a provider, region factory, or `@org.hibernate.annotations.Cache`, nothing is actually cached
Talk about region-level tuning, distributed invalidation, JCache vs Hibernate-native SPIs, and how to verify hit ratios in production
Interview-ready guide
Interview answer
Hibernate L2 is provider-agnostic. The modern path is JCache plus a provider — Caffeine for single JVMs, Hazelcast or Infinispan for clusters.
Configuration steps:
- Enable
use_second_level_cacheanduse_query_cachein application.yml - Set
region.factory_classtoJCacheRegionFactory - Add the provider on the classpath and point
javax.cache.providerat it - Tune regions in the provider's own config — size, TTL, eviction policy
Annotations:
- Use
@org.hibernate.annotations.Cache(usage = READ_WRITE, region = "...")on entities - JPA's
@Cacheablealone does nothing — the Hibernate SPI annotation is required - Annotate
@OneToManycollections separately - Opt queries in with
HINT_CACHEABLEand a named region
Choosing a provider:
- Single instance — Caffeine; fastest in-process cache on the JVM
- Multiple pods — Hazelcast for easy embedded clustering, Infinispan for transactional consistency
- Reference data larger than heap — Ehcache 3 with offheap tier
Verification:
- Enable SQL logging; second call to the same query should not fire SQL
- Turn on
generate_statisticsand expose hit/miss counts via Actuator - Target > 80% hit ratio for cached entities; below that, retune or remove the cache
Configuring L2 + Query Cache — Providers, Regions, and Tuning
Direct Answer
Enable use_second_level_cache=true and use_query_cache=true in application.yml, choose a JCache (JSR-107) provider — Caffeine for single-instance, Hazelcast or Infinispan for clusters, Ehcache 3 for legacy parity — and annotate cacheable entities with @org.hibernate.annotations.Cache(usage = READ_WRITE, region = "..."). Configure per-region size, TTL, and eviction in the provider config (e.g., caffeine.spec), opt queries into the cache with HINT_CACHEABLE, and turn on generate_statistics plus Actuator. Provider choice depends on topology (single JVM vs cluster), invalidation requirements (broadcast vs local), and operational maturity.
Common Mistakes & Pitfalls
Adding @Cacheable (JPA) and assuming it works — without a provider, region factory, or @org.hibernate.annotations.Cache, nothing is actually cached
Check your understanding
Answer these without looking back at the article.
- How do you migrate an Ehcache 2 setup to JCache + Caffeine without breaking entity caching?
- What's the difference between Hazelcast embedded mode and client/server mode for L2?
- How does Infinispan's TRANSACTIONAL strategy differ from READ_WRITE, and when is it worth the overhead?
- How would you size cache regions for a Product table with 10M rows but a hot set of 50K?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.