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

First Level Cache in Hibernate

Complete guide to Hibernate First Level Cache with architecture, internal workflow, examples, performance benefits, persistence context behavior, and interview questions.

What is First Level Cache?

First Level Cache is Hibernate's built-in cache mechanism.

Every Hibernate Session (or JPA Persistence Context) maintains its own cache.

Whenever an entity is loaded from the database, Hibernate stores it in memory.

Subsequent requests for the same entity are served directly from memory without hitting the database again.

Database Query Once
        ↓
Store in Session Cache
        ↓
Reuse Multiple Times

Why First Level Cache Exists

Imagine a service method:

@Transactional
public void processEmployee() {

    Employee employee1 =
            repository.findById(1L).get();

    Employee employee2 =
            repository.findById(1L).get();

    Employee employee3 =
            repository.findById(1L).get();
}

Without cache:

SELECT ...
SELECT ...
SELECT ...

3 Database Calls

With First Level Cache:

SELECT ...
Cache Hit
Cache Hit

Only 1 Database Call


Real Life Example

Think about a teacher taking attendance.

First time:

Teacher checks school records.

Second time:

Teacher remembers student details.

No need to check records again.

Hibernate behaves similarly.

Database = School Records

Session Cache = Teacher Memory

Where Does First Level Cache Live?

Hibernate Session
        OR
Persistence Context

Every Session has its own cache.


Architecture Diagram

flowchart TD

A[Application]

B[Hibernate Session]

C[First Level Cache]

D[(Database)]

A --> B
B --> C

C -->|Cache Miss| D
D --> C

C --> A

Relationship with Persistence Context

Many developers think:

Persistence Context

and

First Level Cache

are different.

Actually:

Persistence Context
      =
First Level Cache

Hibernate stores managed entities here.


Sample Entity

@Entity
@Table(name = "employees")
public class Employee {

    @Id
    private Long id;

    private String name;

    private Double salary;

}

Example 1 - Cache Hit

@Transactional
public void demo() {

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

    Employee e2 =
            entityManager.find(Employee.class, 1L);
}

Generated SQL:

select * from employees where id=1;

Only one query.

Second call comes from cache.


Internal Flow

flowchart LR

A[find Employee]

B{In Cache?}

C[Return Cached Entity]

D[Execute SQL]

E[Store In Cache]

A --> B

B -->|Yes| C

B -->|No| D
D --> E
E --> C

Detailed Execution

First Call

entityManager.find(Employee.class, 1L);

Hibernate:

Cache Lookup
      ↓
Not Found
      ↓
SQL Executed
      ↓
Store Entity in Cache

SQL:

SELECT * FROM employees WHERE id=1;

Second Call

entityManager.find(Employee.class, 1L);

Hibernate:

Cache Lookup
      ↓
Found
      ↓
Return Cached Object

No SQL.


Object Reference Proof

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

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

System.out.println(e1 == e2);

Output:

true

Same Java Object.


Visualization

Session Cache

+--------------------+
| Employee ID = 1    |
| Name = Venu        |
| Salary = 100000    |
+--------------------+

e1 ----------+
             |
             +------> Same Object
             |
e2 ----------+

First Level Cache and Dirty Checking

These two concepts work together.

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

employee.setSalary(200000);

Entity already exists in cache.

Hibernate detects changes during commit.

UPDATE employees
SET salary=200000
WHERE id=1;

Cache + Dirty Checking Flow

flowchart TD

A[Load Entity]

B[Store In Cache]

C[Modify Entity]

D[Dirty Check]

E[Generate Update]

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

Example with Spring Data JPA

@Service
@Transactional
public class EmployeeService {

    @Autowired
    private EmployeeRepository repository;

    public void process() {

        Employee e1 =
                repository.findById(1L).get();

        Employee e2 =
                repository.findById(1L).get();

        System.out.println(e1 == e2);
    }
}

Output:

true

One SQL only.


What Happens Across Transactions?

Transaction 1

Employee e1 =
        repository.findById(1L).get();

SQL Executes.


Transaction 2

Employee e2 =
        repository.findById(1L).get();

SQL Executes Again.

Why?

Because cache is Session scoped.


Session Scope Diagram

flowchart LR

A[Session 1]

B[First Level Cache]

C[(DB)]

D[Session 2]

E[New First Level Cache]

A --> B
B --> C

D --> E
E --> C

Caches are not shared.


Cache Eviction Using detach()

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

entityManager.detach(employee);

Removed from cache.


Diagram

Before detach

Cache
 └── Employee(1)

After detach

Cache
 └── Empty

Example

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

entityManager.detach(e1);

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

SQL Executed Twice.


Clear Entire Cache

entityManager.clear();

Removes all managed entities.


Example

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

entityManager.clear();

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

SQL:

SELECT * FROM employees WHERE id=1;

SELECT * FROM employees WHERE id=1;

Refresh Entity

Suppose another application updates DB.

Current cache contains old value.

entityManager.refresh(employee);

Hibernate reloads data.

SQL:

SELECT * FROM employees WHERE id=1;

Refresh Diagram

flowchart LR

A["Cache Entity"]
B["Database Changed"]
C["EntityManager Refresh"]
D["Reload From Database"]

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

Batch Processing Issue

Large batches can fill cache.

Example:

for(Employee e : employees){

    e.setSalary(1000);
}

Suppose:

100,000 Employees

All remain in memory.

Potential:

OutOfMemoryError

Best Practice

for(Employee e : employees){

    e.setSalary(1000);

    if(count % 50 == 0){

        entityManager.flush();

        entityManager.clear();
    }
}

Memory Visualization

Bad:

Cache

Employee1
Employee2
Employee3
...
Employee100000

Good:

Process 50
Flush
Clear

Process Next 50
Flush
Clear

First Level Cache vs Second Level Cache

Feature First Level Cache Second Level Cache
Default Yes No
Scope Session Application
Shared No Yes
Enabled Automatic Configuration Required
Storage Memory Memory/Redis/Ehcache
Lifetime Session Across Sessions

Complete Lifecycle Diagram

flowchart TD

A[Find Entity]

B{Exists In Cache?}

C[Return Entity]

D[SQL Query]

E[Store In Cache]

F[Modify Entity]

G[Dirty Checking]

H[Update SQL]

A --> B

B -->|Yes| C

B -->|No| D

D --> E

E --> C

C --> F

F --> G

G --> H

Performance Benefits

Without Cache:

100 Entity Reads
=
100 Database Calls

With Cache:

100 Entity Reads
=
1 Database Call
+
99 Cache Hits

Benefits:

✅ Reduced Database Load

✅ Faster Response Time

✅ Fewer Network Calls

✅ Better Throughput


Common Interview Questions

Q1. What is First Level Cache?

Session-scoped cache maintained by Hibernate.


Q2. Is First Level Cache enabled by default?

Yes.

Always enabled.


Q3. Can we disable First Level Cache?

Not completely.

It is part of Session/Persistence Context.


Q4. What is stored inside First Level Cache?

Managed Entities
Snapshots
Proxy Objects

Q5. Is First Level Cache shared?

No.

Each Session has its own cache.


Q6. Difference between clear() and detach()?

detach(entity);

Removes one entity.

clear();

Removes all entities.


Q7. Why does Hibernate return same object reference?

Because cached entity instance is reused.

e1 == e2

returns:

true

Best Practices

✅ Keep transactions short

✅ Use clear() in batch jobs

✅ Understand Session boundaries

✅ Use refresh() when data changes externally

✅ Leverage cache to reduce database hits

❌ Don't keep huge persistence contexts

❌ Don't assume cache works across transactions

❌ Don't confuse First Level Cache with Redis/Ehcache


Summary

First Level Cache is Hibernate's Session-level cache.

Workflow:

Entity Request
      ↓
Check Cache
      ↓
Cache Miss → Database
      ↓
Store In Cache
      ↓
Future Requests
      ↓
Cache Hit

Remember:

First Level Cache
=
Persistence Context
=
Managed Entity Store

And it is the foundation for:

✔ Dirty Checking

✔ Entity Lifecycle Management

✔ Performance Optimization

✔ Hibernate's ORM Magic