By WebNest Studio Engineering Team
Advanced Java Tutorial
Hibernate Caching: First-Level and Second-Level
Repeatedly hitting the database for data that hasn't changed is wasted work. Hibernate has two built-in caching layers that reduce redundant SQL, each operating at a different scope.
First-Level Cache (Session Cache)
Always on, and scoped to a single Session. Within one Session, calling session.get(Student.class, 1) twice only issues one SQL query — the second call returns the same managed object straight from the Session's internal cache, without touching the database again. This cache is cleared automatically when the Session closes, so it never leaks data between unrelated units of work.
Second-Level Cache (SessionFactory Cache)
Optional, and scoped to the whole SessionFactory — shared across every Session in the application, so entities cached by one user's request can be reused by another's. It requires a caching provider (commonly Ehcache or Caffeine) and must be explicitly enabled per entity with @Cacheable. Because it's shared, entries need a clear invalidation strategy so stale data isn't served after an update — Hibernate handles this automatically for entities it manages, evicting or updating cached entries when they change through Hibernate itself.
Query Cache
A companion to the second-level cache that caches the results of specific queries (a list of ids matching a WHERE clause), not just individual entities. It only becomes useful once the second-level cache is enabled, since the query cache stores entity ids and relies on the second-level cache to supply the actual entity data for those ids.
Example
Enabling the second-level cache for an entity (with Ehcache as the provider)
<!-- Maven dependencies: hibernate-jcache + ehcache -->
<!-- hibernate.cfg.xml -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.jcache.JCacheRegionFactory</property>
import jakarta.persistence.*;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Student {
@Id @GeneratedValue private long id;
private String name;
}
// First session: hits the database, then populates the 2nd-level cache
Student s1 = session1.get(Student.class, 1);
// A completely different, later session: served from the 2nd-level cache, no SQL executed
Student s2 = session2.get(Student.class, 1);
Hibernate: select * from student where id=? (only on the first session's load)
Common Mistakes
- Assuming the second-level cache is on by default — it requires an explicit provider dependency, configuration, and @Cacheable on each entity.
- Caching frequently-updated entities aggressively, causing readers to see stale data more often than the performance gain is worth.
- Confusing the first-level (always-on, per-Session) cache with the second-level (opt-in, shared) cache when reasoning about staleness.
- Enabling the query cache without enabling the second-level cache first, which produces little benefit since the query cache only stores ids.
Exercise
Using the lesson's Enabling the second-level cache for an entity (with Ehcache as the provider) example, create a small implementation or design sketch that demonstrates First-level cache is automatic, scoped to one Session, and cannot be disabled.. Add a test case or scenario that would catch Assuming the second-level cache is on by default — it requires an explicit provider dependency, configuration, and @Cacheable on each entity., and describe the expected result.
Show hints
- Start with First-Level Cache (Session Cache) and compare your approach with Enabling the second-level cache for an entity (with Ehcache as the provider). Identify the decision or behavior the lesson recommends.
- Walk through your scenario step by step. Confirm that it follows First-level cache is automatic, scoped to one Session, and cannot be disabled. and that it would catch the failure described by Assuming the second-level cache is on by default — it requires an explicit provider dependency, configuration, and @Cacheable on each entity..
Quick quiz
1. Which choice is a mistake to avoid in Hibernate Caching: First-Level and Second-Level?
- A. First-level cache is automatic, scoped to one Session, and cannot be disabled.
- B. Assuming the second-level cache is on by default — it requires an explicit provider dependency, configuration, and @Cacheable on each entity.
- C. Caching frequently-updated entities aggressively, causing readers to see stale data more often than the performance gain is worth.
Show answer
B. Avoid this approach: Assuming the second-level cache is on by default — it requires an explicit provider dependency, configuration, and @Cacheable on each entity. The lesson recommends: First-level cache is automatic, scoped to one Session, and cannot be disabled.
Interview questions
How would you apply the guidance in First-Level Cache (Session Cache) to a real task, and what failure would you guard against?
Show answer
First-level cache is automatic, scoped to one Session, and cannot be disabled. Apply this in First-Level Cache (Session Cache); the example Enabling the second-level cache for an entity (with Ehcache as the provider) shows one way to do it. Avoid Assuming the second-level cache is on by default — it requires an explicit provider dependency, configuration, and @Cacheable on each entity. and explain how your implementation or design prevents that failure.
Key Points to Remember
- First-level cache is automatic, scoped to one Session, and cannot be disabled.
- Second-level cache is optional, shared across the whole SessionFactory, and needs a provider like Ehcache plus @Cacheable per entity.
- The query cache stores query result ids and depends on the second-level cache for the actual entity data.
- Cache aggressively-read, rarely-changed entities; avoid caching data that changes often.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering