Full Stack • Java • System Design • Cloud • AI Engineering

Hibernate Second Level Cache

Complete guide to Hibernate Second Level Cache with architecture, cache providers, Redis/Ehcache integration, cache strategies, examples, performance optimization, and interview questions.

Second Level Cache (L2 Cache) is a cache shared across multiple Hibernate Sessions.

Unlike First Level Cache:

First Level Cache
      ↓
Session Scoped

Second Level Cache:

Application Scoped

Meaning:

Session 1
Session 2
Session 3
Session N
       ↓
Shared Cache

Multiple sessions can reuse cached data without querying the database.


Why Do We Need Second Level Cache?

Consider this scenario:

Session 1
Employee employee =
    entityManager.find(Employee.class, 1L);

SQL:

SELECT * FROM employees WHERE id = 1;

Session ends.

Later:

Session 2
Employee employee =
    entityManager.find(Employee.class, 1L);

Again:

SELECT * FROM employees WHERE id = 1;

Problem:

First Level Cache
Dies with Session

Database keeps getting hit repeatedly.

Second Level Cache solves this.


Real World Example

Imagine Netflix.

Movie metadata:

Movie Name
Genre
Duration
Rating

Millions of users request it.

Without cache:

Every Request
      ↓
Database

Disaster.

Instead:

Database
    ↓
Redis / Cache
    ↓
Millions of Requests

Hibernate L2 Cache works similarly.


Cache Levels Overview

flowchart TD

A["Application"]

B["First Level Cache"]

C["Second Level Cache"]

D["Database"]

A --> B

B -->|Miss| C

C -->|Miss| D

D --> C

C --> B

First Level vs Second Level Cache

Feature First Level Cache Second Level Cache
Scope Session Application
Shared No Yes
Default Enabled Disabled
Lifetime Session Application
Storage JVM Memory Cache Provider
Configuration None Required

Architecture

flowchart LR

A["Session 1"]

B["Session 2"]

C["Session 3"]

D["Second Level Cache"]

E["Database"]

A --> D
B --> D
C --> D

D --> E

Cache Providers

Hibernate itself does not store cache.

It delegates to providers.

Popular options:

Provider Usage
Ehcache Most Popular
Redis Distributed Cache
Hazelcast Cluster Cache
Infinispan Enterprise
Caffeine Lightweight

How Second Level Cache Works

First Request

employeeRepository.findById(1L);

Flow:

First Level Cache → Miss
Second Level Cache → Miss
Database → Hit
Store in L2 Cache
Return Entity

Second Request

Different Session:

employeeRepository.findById(1L);

Flow:

First Level Cache → Miss
Second Level Cache → Hit
Return Entity

No SQL.


Detailed Flow

flowchart TD

A["Find Entity"]

B["Check First Level Cache"]

C["Check Second Level Cache"]

D["Database"]

E["Store In L2 Cache"]

F["Return Entity"]

A --> B

B -->|Miss| C

C -->|Hit| F

C -->|Miss| D

D --> E

E --> F

Sample Entity

@Entity
@Table(name = "employees")
@Cacheable
@org.hibernate.annotations.Cache(
        usage = CacheConcurrencyStrategy.READ_WRITE
)
public class Employee {

    @Id
    private Long id;

    private String name;

    private Double salary;
}

Enable Second Level Cache

application.yml

spring:
  jpa:
    properties:
      hibernate:
        cache:
          use_second_level_cache: true
          use_query_cache: true

Maven Dependency

Ehcache

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

Example

First Request

@Transactional
public Employee getEmployee() {

    return repository.findById(1L)
                     .orElseThrow();
}

Generated SQL:

SELECT *
FROM employees
WHERE id = 1;

Second Request

Another transaction:

@Transactional
public Employee getEmployeeAgain() {

    return repository.findById(1L)
                     .orElseThrow();
}

SQL:

No SQL

Served from cache.


Visualization

Request 1

User
 ↓
Hibernate
 ↓
Database
 ↓
Cache

--------------------------------

Request 2

User
 ↓
Hibernate
 ↓
Cache
 ↓
Response

Cache Region

Each entity has a cache region.

Example:

@Entity
@Cacheable
@Cache(
    usage = CacheConcurrencyStrategy.READ_WRITE,
    region = "employee-region"
)
public class Employee {
}

Cache Region Diagram

Second Level Cache

+--------------------+
| employee-region    |
+--------------------+

+--------------------+
| customer-region    |
+--------------------+

+--------------------+
| order-region       |
+--------------------+

Cache Concurrency Strategies

Very important interview topic.


READ_ONLY

Best performance.

Only for immutable data.

@Cache(
    usage = CacheConcurrencyStrategy.READ_ONLY
)

Example:

Country
State
Currency
Language

Never changes.


READ_WRITE

Most commonly used.

Supports updates safely.

@Cache(
    usage = CacheConcurrencyStrategy.READ_WRITE
)

Best for:

Employee
Customer
Product

NONSTRICT_READ_WRITE

Allows stale data briefly.

Faster than READ_WRITE.

@Cache(
    usage =
      CacheConcurrencyStrategy.NONSTRICT_READ_WRITE
)

Good for:

Mostly Read Data

TRANSACTIONAL

Used with JTA.

Rarely used.

@Cache(
    usage =
      CacheConcurrencyStrategy.TRANSACTIONAL
)

Strategy Comparison

Strategy Updates Consistency Performance
READ_ONLY No High Fastest
READ_WRITE Yes High Good
NONSTRICT_READ_WRITE Yes Medium Better
TRANSACTIONAL Yes Highest Slower

What Happens During Update?

Suppose:

employee.setSalary(200000);

Hibernate updates:

UPDATE employees
SET salary = 200000
WHERE id = 1;

Then:

Invalidate Cache

or

Update Cache Entry

depending on strategy.


Update Flow

flowchart TD

A["Update Entity"]

B["Database Update"]

C["Cache Update"]

D["Future Reads"]

A --> B

B --> C

C --> D

Query Cache

Entity Cache:

findById()

results cached.


Query Cache:

findAll()

results cached.


Enable:

hibernate:
  cache:
    use_query_cache: true

Example

Query query =
 entityManager.createQuery(
     "select e from Employee e");

query.setHint(
 "org.hibernate.cacheable",
 true
);

Entity Cache vs Query Cache

Feature Entity Cache Query Cache
Stores Entities Query Results
findById Yes No
JPQL No Yes
Native Query No Optional

Redis Architecture

Enterprise systems often use Redis.

flowchart LR

A["Application 1"]

B["Application 2"]

C["Application 3"]

D["Redis"]

E["Database"]

A --> D
B --> D
C --> D

D --> E

Benefits:

Shared Across Servers
Distributed
High Performance

Performance Example

Without Cache:

1000 Requests

1000 Database Calls

With Cache:

1000 Requests

1 Database Call

999 Cache Hits

What Should Be Cached?

Good Candidates:

✅ Country

✅ State

✅ Currency

✅ Product Catalog

✅ Employee Master Data

✅ Configuration Tables


Avoid Caching:

❌ Frequently Updated Data

❌ Real-Time Trading Data

❌ Session Data

❌ Highly Volatile Data


Common Problems

Stale Data

Database changed externally.

Cache contains old value.

Solution:

Cache Eviction
TTL
Refresh Strategy

Cache Stampede

Thousands of requests.

Cache expired.

Everyone hits DB simultaneously.

Solution:

Redis
Locking
Warm-up Cache

Best Practices

✅ Cache read-heavy entities

✅ Use READ_ONLY whenever possible

✅ Use Redis for distributed environments

✅ Monitor cache hit ratio

✅ Define cache regions properly


Interview Questions

Q1. What is Second Level Cache?

Application-wide shared Hibernate cache.


Q2. Is it enabled by default?

No.

Must be configured.


Q3. Difference between First and Second Level Cache?

First Level Cache
    Session Scoped

Second Level Cache
    Application Scoped

Q4. Which cache is checked first?

1. First Level Cache

2. Second Level Cache

3. Database

Q5. What is CacheConcurrencyStrategy?

Defines consistency behavior.

Examples:

READ_ONLY

READ_WRITE

NONSTRICT_READ_WRITE

TRANSACTIONAL

Q6. Which strategy is most used?

READ_WRITE

Q7. Which strategy gives best performance?

READ_ONLY

Complete End-to-End Flow

flowchart TD

A["Application Request"]

B["First Level Cache"]

C["Second Level Cache"]

D["Database"]

E["Store In Cache"]

F["Return Entity"]

A --> B

B -->|Miss| C

C -->|Miss| D

D --> E

E --> F

C -->|Hit| F

Summary

Second Level Cache is Hibernate's shared application-level cache.

Workflow:

Request
   ↓
First Level Cache
   ↓
Second Level Cache
   ↓
Database

Key Benefits:

✅ Reduced Database Load

✅ Faster Response Time

✅ Improved Scalability

✅ Better Throughput

Remember:

First Level Cache
     =
Session Scope

Second Level Cache
     =
Application Scope

In production systems, Redis + Hibernate Second Level Cache is one of the most powerful techniques for reducing database traffic and improving application performance.