Hibernate - Enable and Implement First and Second Level Cache
Hibernate is a powerful ORM (Object-Relational Mapping) framework that helps Java developers interact with relational databases using Java objects instead of SQL queries. One of the major reasons Hibernate delivers high performance is its advanced caching mechanism, which minimizes unnecessary database hits.

Hibernate provides two types of caches:
- First-Level Cache (Session-level): Always enabled
- Second-Level Cache (SessionFactory-level): Optional / Configurable
A proper understanding of both caches is essential for building efficient and scalable enterprise applications.
Why Caching is So Important for Improving Application Performance?
Database operations are expensive. Caching helps by storing frequently accessed data in memory, thereby reducing the need for repetitive database trips.
- Faster Data Access: Retrieving data from memory is significantly faster than hitting the database.
- Improved Throughput: Fewer SQL queries, more user requests handled per second.
- Better Scalability: Applications can handle increased load without requiring more hardware
- Reduced Database Load: Caching minimizes stress on the database server, reducing resource consumption.
First-Level Cache (L1 Cache)
Hibernate’s first-level cache is built into every Session. It cannot be disabled. It stores entities loaded during the lifecycle of that session.
How It Works
- Every time you call session.get() or session.find(), Hibernate first checks the Session cache.
- If the entity is already present, no SQL query is executed.
- Only when the entity is not available does Hibernate hit the database.
Internal Implementation
Hibernate maintains a persistence context (similar to a HashMap), mapping:
Entity Identifier -> Entity Instance
Example:
Person p1 = session.get(Person.class, 1); // Hits DB
Person p2 = session.get(Person.class, 1); // Returned from L1 Cache
Advantages of First-Level Cache
- Better Performance: Minimizes database hits by caching entities in the session.
- Data Consistency: Maintains consistent entity state within the same session.
- No Setup Needed: Enabled by default and managed automatically by Hibernate.
Disadvantages of First-Level Cache
- Applies only within a single session
- Cannot be shared across sessions
- Can cause memory usage if session stays open too long
Second-Level Cache (L2 Cache)
Second-Level Cache is a process-wide, shared cache associated with the SessionFactory. Unlike First-Level Cache, L2 Cache.
- Must be explicitly enabled
- Must be backed by a caching provider like: Ehcache ,Infinispan ,Hazelcast and JCache (JSR-107)
When to Use L2 Cache
- Multiple sessions access the same frequently-used data
- Read-mostly or read-heavy applications
- Low-frequency updates to cached entities
How It Works
- Hibernate loads an entity -> checks second-level cache.
- If found -> returned immediately.
- If not -> Hibernate fetches from DB and stores a copy in L2 cache for future sessions
Enabling Second-Level Cache in Hibernate
Step 1: Add Cache Provider Dependency
Example: Ehcache 3 using JCache
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
Step 2: Enable Second-Level Cache
hibernate.cfg.xml / properties
# Enable L2 Cache
hibernate.cache.use_second_level_cache=true
# Enable Query Cache (optional)
hibernate.cache.use_query_cache=true
# Set region factory (JCache)
hibernate.cache.region.factory_class=org.hibernate.cache.jcache.JCacheRegionFactory
# JCache configuration file
hibernate.javax.cache.uri=ehcache.xml
Step 3: Mark Entities as Cacheable
Minimum JPA Annotation
@Entity
@Cacheable
public class Person {
@Id
private Long id;
private String name;
}
Hibernate-Specific Annotation
@Entity
@Cacheable
@org.hibernate.annotations.Cache(
usage = CacheConcurrencyStrategy.READ_WRITE,
region = "person-cache"
)
public class Person {
@Id
private Long id;
private String name;
}
Step 4: Enable Query Cache (If needed)
Query query = session.createQuery("FROM Person WHERE name = :name");
query.setParameter("name", "John");
query.setCacheable(true); // enables query cache
List<Person> results = query.list();
Note: Query cache stores IDs, not entities. Entities themselves are stored in second-level cache.
Advantages of Second-Level Cache
- Reduces database queries by serving data from memory.
- Improves performance with faster data access.
- Shared across sessions, unlike first-level cache.
- Enhances scalability by lowering DB load.
Disadvantages of Second-Level Cache
- Risk of stale data if DB updates occur outside Hibernate.
- Not ideal for write-heavy applications due to frequent invalidation.
- Consumes more memory, increasing heap usage.
- Adds configuration complexity (providers, regions, strategies).