Enabling Hibernate Second‑Level Cache with Ehcache: A Production‑Ready Architecture Note
Implement Hibernate’s second‑level cache with Ehcache in a single‑node, read‑heavy environment. This architecture note covers minimal configuration, entity annotations, operational checks, failure modes, and when to redesign for optimal performance.
28 Sept 2025, 00:07 UTC

Problem Statement
Read‑heavy applications using Hibernate often suffer from database round‑trips for immutable or slowly changing data. The Hibernate second‑level cache can dramatically reduce latency and load, but configuring it correctly is non‑trivial. This guide shows the minimal, production‑ready design for enabling Hibernate’s second‑level cache with Ehcache, covering requirements, trust boundaries, operational checks, failure modes, and when a redesign is necessary.
Requirements
- Hibernate 5.4 or 6.x (ensure the cache integration module is present).
- Ehcache 2.x for Hibernate 5.4 or Ehcache 3.x with the
hibernate-ehcachemodule for Hibernate 6. - Serializable entity classes for cache storage.
- JMX access for monitoring cache statistics.
The Smallest Suitable Design
For a single‑node, read‑heavy workload, a local Ehcache region factory is sufficient. The following files illustrate the minimal configuration.
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="hibernate.cache.use_query_cache">false</property>
</session-factory>
</hibernate-configuration>
Ehcache Configuration (ehcache.xml)
<ehcache xmlns="http://www.ehcache.org/v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">
<cache alias="org.hibernate.cache.spi.UpdateTimestampsCache"
eternal="false"
maxEntriesLocalHeap="10000"
overflowToDisk="false"
statistics="true"/>
<cache alias="org.hibernate.cache.spi.RegionFactory"
eternal="false"
maxEntriesLocalHeap="5000"
overflowToDisk="false"
statistics="true"/>
<cache alias="com.example.domain.User"
eternal="false"
maxEntriesLocalHeap="20000"
overflowToDisk="false"
statistics="true"/>
</ehcache>
Each cache region corresponds to an entity or query. The maxEntriesLocalHeap should be sized to fit within the JVM heap; setting it too high can trigger OutOfMemoryError. The statistics flag enables hit/miss counters exposed via JMX.
Entity Annotation Example
Mark the entity as cacheable and choose an appropriate concurrency strategy.
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) // or READ_WRITE for mutable data
public class User implements Serializable {
@Id
private Long id;
private String name;
// getters/setters
}
For mutable entities, READ_WRITE ensures Hibernate performs cache evictions on updates. READ_ONLY is safe for immutable data and offers the best performance.
Trust and Data Boundaries
The cache is isolated from the database. All writes go through the Hibernate session, which triggers automatic eviction or replication events to keep the cache consistent. Because the cache never reads data directly from the database, there is no risk of stale reads as long as the session lifecycle is respected.
Operational Checks
- Hit/Miss Ratio Monitoring
Use JMX to query the Ehcache statistics MBeans. Example via JConsole:- Connect to the JVM.
- Navigate to
org.hibernate.cache.ehcache→com.example.domain.User→CacheStatistics. - Verify
cacheHitsandcacheMissesvalues.
- Integration Test Verification
Write a test that performs a query twice. Assert that the second query records a cache hit by checking thecacheHitscounter before and after the query. - Eviction Policy Validation
Insert a large number of entities to trigger the LRU policy. Observe that older entries are evicted and the hit ratio stabilizes.
Failure Modes and Mitigations
- Cache Misses Due to Eviction
If the configured heap size is too small, frequent evictions will reduce hit ratios. Mitigate by increasingmaxEntriesLocalHeapor adding disk overflow if acceptable. - Serialization Bottlenecks
Large entity graphs increase serialization time. Keep cached entities lean; avoid caching collections unless necessary. - Stale Data in Clustered Environments
Local Ehcache does not propagate updates across nodes. For multi‑node deployments, switch to a distributed cache (e.g., Infinispan) or enable Ehcache’sdistributedmode.
When to Redesign
If any of the following conditions arise, consider revising the cache strategy:
- Read/write ratio shifts toward more updates.
- Entity size grows beyond a few kilobytes.
- Application scales to multiple JVMs requiring cache coherence.
- Observed cache hit ratio drops below 70% over sustained periods.
- Memory pressure causes frequent
OutOfMemoryErrordue to cache growth.
Practical Verification Checklist
| Check | What to Do | Expected Result |
|---|---|---|
| JMX Hit Count | Query cacheHits via JConsole | Increment after a cached read |
| Integration Test | Run test that asserts hit count > 0 | Passes |
| Eviction Policy | Insert > maxEntriesLocalHeap entities | Older entries evicted, hit ratio stabilizes |
Conclusion
By setting hibernate.cache.use_second_level_cache to true, using the appropriate Ehcache region factory, marking entities with @Cacheable and a suitable concurrency strategy, and sizing the cache to the JVM heap, you obtain a minimal, production‑ready second‑level cache. Continuous monitoring via JMX and periodic integration tests ensure that the cache remains effective and that any degradation triggers a timely redesign.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.