Dirty Checking in Hibernate
Complete guide to Hibernate Dirty Checking mechanism with lifecycle, internal workflow, examples, performance considerations, and interview questions.
What is Dirty Checking?
Dirty Checking is one of Hibernate's most powerful features.
It automatically detects changes made to a managed entity and synchronizes those changes with the database during transaction commit.
Instead of writing:
employeeRepository.update(employee);
Hibernate automatically executes the UPDATE statement.
This significantly reduces boilerplate code.
Real Life Example
Imagine you open a Google Doc.
You make some changes.
You don't click "Save" every second.
Google automatically detects modifications and saves them.
Hibernate Dirty Checking works exactly the same way.
Google Docs
|
Detect Changes
|
Auto Save
Hibernate
|
Detect Changes
|
Auto Update DB
Why Dirty Checking?
Without Dirty Checking:
Employee employee = repository.findById(1L).get();
employee.setSalary(100000);
repository.save(employee);
Developer must remember to save every change.
With Dirty Checking:
Employee employee = repository.findById(1L).get();
employee.setSalary(100000);
// No save()
Hibernate updates database automatically.
Prerequisites
Dirty Checking works only when:
✅ Entity is Managed
✅ Inside Persistence Context
✅ Transaction is Active
❌ Detached Entity
❌ Closed Session
❌ No Transaction
Entity States Refresher
stateDiagram-v2
[*] --> Transient
Transient --> Managed : persist()
Managed --> Detached : session close
Detached --> Managed : merge()
Managed --> Removed : remove()
Removed --> [*]
Dirty Checking only works for:
Managed State
Sample Entity
@Entity
@Table(name = "employees")
public class Employee {
@Id
private Long id;
private String name;
private Double salary;
private String department;
// getters setters
}
Basic Example
Service Layer
@Transactional
public void updateSalary() {
Employee employee =
employeeRepository.findById(1L).get();
employee.setSalary(120000.0);
}
Notice:
employeeRepository.save(employee);
is missing.
Still Hibernate executes:
UPDATE employees
SET salary = 120000
WHERE id = 1;
How Dirty Checking Works Internally
When entity is loaded:
Employee employee =
repository.findById(1L).get();
Hibernate creates:
Managed Entity
and
Snapshot Copy
Example:
Database
ID=1
Name=Venu
Salary=80000
Hibernate stores:
Managed Object
ID=1
Name=Venu
Salary=80000
Snapshot:
Snapshot
ID=1
Name=Venu
Salary=80000
Entity Modified
employee.setSalary(120000);
Now:
Managed Object
Salary=120000
Snapshot remains:
Snapshot
Salary=80000
During Commit
Hibernate compares:
Managed Object
VS
Snapshot
If difference found:
UPDATE employees
SET salary = 120000
WHERE id = 1;
This comparison process is called:
Dirty Checking
Internal Workflow Diagram
flowchart TD
A[Load Entity]
B[Create Snapshot]
C[Modify Entity]
D[Transaction Commit]
E[Compare Snapshot]
F[Dirty?]
G[Generate UPDATE]
H[Execute SQL]
I[No SQL]
A --> B
B --> C
C --> D
D --> E
E --> F
F -->|Yes| G
G --> H
F -->|No| I
Example Flow
@Transactional
public void updateEmployee() {
Employee employee =
repository.findById(1L).get();
employee.setDepartment("Architecture");
}
Generated SQL:
select * from employees where id=1;
update employees
set department='Architecture'
where id=1;
No Changes Scenario
@Transactional
public void checkEmployee() {
Employee employee =
repository.findById(1L).get();
}
Generated SQL:
select * from employees where id=1;
No update executed.
Because nothing changed.
Dirty Checking with Multiple Fields
@Transactional
public void updateEmployee() {
Employee employee =
repository.findById(1L).get();
employee.setName("Venugopal");
employee.setSalary(150000.0);
employee.setDepartment("Platform");
}
Generated SQL:
UPDATE employees
SET
name=?,
salary=?,
department=?
WHERE id=?;
Dirty Checking and Flush
Hibernate performs Dirty Checking during:
flush()
or
transaction commit
Example:
employee.setSalary(150000);
entityManager.flush();
Immediately executes:
UPDATE employees
SET salary=150000
WHERE id=1;
Flush Lifecycle
flowchart LR
A[Entity Loaded]
B[Entity Modified]
C[Flush]
D[Dirty Check]
E[Generate SQL]
F[Commit]
A --> B
B --> C
C --> D
D --> E
E --> F
Dirty Checking with EntityManager
@Transactional
public void updateEmployee() {
Employee employee =
entityManager.find(Employee.class, 1L);
employee.setSalary(100000);
}
No explicit update required.
Dirty Checking Does NOT Work
Detached Entity
Employee employee =
repository.findById(1L).get();
entityManager.detach(employee);
employee.setSalary(200000);
No update.
Because entity is detached.
Diagram
flowchart LR
A[Managed Entity]
B[detach]
C[Detached Entity]
D[Modify]
E[Commit]
F[No Update]
A --> B
B --> C
C --> D
D --> E
E --> F
Reattach Using Merge
Employee employee =
repository.findById(1L).get();
entityManager.detach(employee);
employee.setSalary(200000);
entityManager.merge(employee);
Now update happens.
Dirty Checking Performance Impact
Suppose Session contains:
10000 Entities
During flush:
Hibernate compares
all snapshots
with current objects
Can become expensive.
Optimization Techniques
Read Only Transaction
@Transactional(readOnly = true)
public Employee getEmployee() {
return repository.findById(1L).get();
}
Hibernate skips dirty checking.
Performance improves.
Clear Persistence Context
entityManager.clear();
Removes managed entities.
Useful for large batch jobs.
Batch Processing
for(Employee employee : employees){
employee.setSalary(1000);
if(count % 50 == 0){
entityManager.flush();
entityManager.clear();
}
}
Prevents memory issues.
Dirty Checking vs save()
Dirty Checking
employee.setSalary(100000);
Automatic.
Explicit Save
repository.save(employee);
Manual.
Comparison
| Feature | Dirty Checking | save() |
|---|---|---|
| Automatic | Yes | No |
| Less Code | Yes | No |
| Managed Entity | Required | Not Required |
| Uses Persistence Context | Yes | No |
| Performance | Better | Depends |
Interview Questions
Q1: What is Dirty Checking?
Hibernate mechanism that automatically detects entity changes and updates database during flush/commit.
Q2: When does Dirty Checking occur?
During:
flush()
transaction commit
Q3: Does Dirty Checking work on detached entities?
No.
Only managed entities participate.
Q4: How does Hibernate know entity changed?
Using:
Snapshot Comparison
Current state is compared against original snapshot.
Q5: How can we disable Dirty Checking?
@Transactional(readOnly = true)
or
entityManager.detach(entity);
Best Practices
✅ Keep transactions short
✅ Use readOnly transactions for queries
✅ Flush periodically in batch jobs
✅ Avoid huge persistence contexts
✅ Understand entity states
❌ Don't keep thousands of entities managed
❌ Don't rely on Dirty Checking outside transaction
Summary
Dirty Checking is Hibernate's automatic change detection mechanism.
Workflow:
Load Entity
↓
Create Snapshot
↓
Modify Entity
↓
Flush / Commit
↓
Compare Snapshot
↓
Generate UPDATE SQL
Key Rule:
Dirty Checking Works Only For Managed Entities
Inside Active Transaction
This is one of the biggest reasons Hibernate reduces boilerplate code and makes database operations simpler.