Hibernate Performance

Second-Level Cache in Hibernate

Configure Hibernate's optional SessionFactory-level cache so suitable entity data can be reused across multiple sessions.

What Is the Second-Level Cache?

The second-level cache is shared by sessions created from the same SessionFactory. When an eligible entity is loaded in one session, Hibernate may store its state in a cache region. A later session can reuse that state instead of querying the database.

Session 1SessionFactory cacheSession 2
Important: the cache stores entity state, not a live entity object shared between sessions. Each session still manages its own entity instance and persistence context.

Enable Second-Level Caching

Second-level caching is not useful until a cache region factory and a cache provider are configured. Hibernate 6 provides the hibernate-jcache integration for JCache-compatible providers.

<dependency>
  <groupId>org.hibernate.orm</groupId>
  <artifactId>hibernate-jcache</artifactId>
  <version>6.6.9.Final</version>
</dependency>
<dependency>
  <groupId>org.ehcache</groupId>
  <artifactId>ehcache</artifactId>
  <version>3.10.8</version>
</dependency>

Keep provider versions compatible with the Hibernate and Jakarta dependencies used by the application. Other integrations, such as Infinispan, may be more appropriate for clustered deployments.

<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">jcache</property>
<property name="hibernate.javax.cache.provider">
  org.ehcache.jsr107.EhcacheCachingProvider
</property>
<property name="hibernate.javax.cache.uri">ehcache.xml</property>

Configuration property names vary across Hibernate generations and JCache integrations. Confirm the exact settings for the selected Hibernate version and provider.

Mark an Entity as Cacheable

Enabling the cache does not mean every entity should be cached. Mark suitable entities explicitly and choose a concurrency strategy.

import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Country {
    @Id
    private Long id;

    private String name;
}

READ_ONLY suits immutable reference data. For data that changes, select a strategy only after understanding update frequency, concurrency, and consistency requirements.

Cache Concurrency Strategies

StrategyTypical use
READ_ONLYImmutable data that never changes after deployment.
NONSTRICT_READ_WRITEData that changes rarely and can tolerate a short stale-data window.
READ_WRITEMutable data requiring coordinated cache updates through a supported strategy.
TRANSACTIONALProvider and transaction environment support transactional cache semantics.
Consistency warning: Hibernate cannot automatically know about updates made directly by another application, SQL script, or service. External changes can leave cache entries stale until they expire or are evicted.

Second-Level Cache Example

The first session loads the entity. After it closes, a second session can use the shared cache when the entity is cacheable and the provider has retained the entry.

try (Session firstSession = factory.openSession()) {
    Country first = firstSession.find(Country.class, 1L);
}

try (Session secondSession = factory.openSession()) {
    Country second = secondSession.find(Country.class, 1L);
}

The second lookup is eligible for a second-level cache hit. The actual result depends on entity cache metadata, cache configuration, expiry, invalidation, and whether the first-level cache already contains the entity.

Cache Regions and Collections

Hibernate organizes cached data into regions. An entity hierarchy has an entity region, while a cached collection has a collection-region name derived from its role.

@OneToMany(mappedBy = "department")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Employee> employees = new HashSet<>();

Cache a collection only when its access pattern and invalidation behavior justify the memory and operational cost. Query-result caching is separate and should not be confused with entity caching.

Evict and Manage Cached Data

Use the Hibernate cache API when an administrative action requires explicit eviction.

SessionFactory sessionFactory = ...;

sessionFactory.getCache()
    .evictEntityData(Country.class, 1L);

sessionFactory.getCache()
    .evictEntityData(Country.class);

sessionFactory.getCache().evictAllRegions();

Eviction APIs are powerful and can affect active application traffic. Prefer correct cache invalidation and provider configuration over frequent manual eviction.

First-Level versus Second-Level Cache

CharacteristicFirst-level cacheSecond-level cache
ScopeOne SessionShared by sessions from one SessionFactory
DefaultEnabled automaticallyRequires a provider and explicit entity configuration
DataManaged entity instancesCached entity state and configured collection data
LifetimeSession or persistence-context lifetimeProvider and region lifetime, subject to expiry and eviction
Main benefitIdentity consistency within a unit of workReuse across sessions and reduced database reads

Cache Providers

Hibernate integrates with external cache implementations rather than being a complete cache database itself.

  • JCache-compatible providers: use the Hibernate JCache integration with a provider such as Ehcache where appropriate.
  • Infinispan: useful for distributed or clustered cache scenarios when its operational model fits the application.
  • Other integrations: verify compatibility, maintenance status, clustering behavior, serialization, and transaction support before adoption.

Older tutorials may mention SwarmCache, OSCache, or JBoss Cache. These names describe historical integrations and should not be copied into a current Hibernate configuration without verifying project compatibility.

Second-Level Cache Best Practices

  • Cache stable, frequently read data rather than every entity.
  • Measure cache hit rate, database load, memory, and stale-data behavior.
  • Choose a concurrency strategy that matches the data's consistency requirements.
  • Do not cache data that changes outside Hibernate unless invalidation is coordinated.
  • Keep cache regions and expiry policies explicit.
  • Test updates, deletes, rollbacks, deployment, and cluster behavior.
  • Remember that query caching is separate from second-level entity caching.
Summary: the second-level cache is an optional SessionFactory-level cache shared across sessions. It can reduce repeated database reads, but only when entity selection, invalidation, provider compatibility, and consistency are designed carefully.