Hibernate Performance

First-Level Cache in Hibernate

Understand Hibernate's automatic Session-level cache, how repeated entity lookups avoid duplicate SQL, and how it differs from the second-level cache.

What Is Caching in Hibernate?

Caching keeps recently used data available so an application can avoid repeating expensive database work. Hibernate provides a first-level cache for every session and can optionally use a shared second-level cache.

First-level cache

Built into every Session, scoped to one persistence context, and enabled by default.

Second-level cache

Optional, shared across sessions, and configured through a compatible cache provider.

What Is the First-Level Cache?

The first-level cache is the persistence context associated with a Hibernate Session. When Hibernate loads an entity, the session keeps the managed instance in memory. A later lookup for the same entity identity in the same session can return that managed instance without another SQL select.

  • It is enabled by default.
  • It belongs to one session and is not shared across sessions.
  • It stores managed entity instances and their state.
  • It is cleared when the session is cleared or closed.
  • It also supports identity consistency: one session normally returns one object instance for a given entity identity.

First-Level Cache Example

The second lookup occurs in the same session and uses the same entity type and identifier.

try (Session session = sessionFactory.openSession()) {
    Employee first = session.find(Employee.class, 101L);
    Employee second = session.find(Employee.class, 101L);

    System.out.println(first == second); // true
}

With SQL logging enabled, Hibernate normally shows one select for the first lookup. The second lookup is resolved from the current session's persistence context.

Scope matters: if the second lookup uses a different session, it has a different first-level cache and may execute another SQL query.

First-Level Cache Lifecycle

  1. A session is opened.
  2. Hibernate loads or persists an entity.
  3. The entity becomes managed in the session's persistence context.
  4. Repeated access to the same identity can use the managed instance.
  5. Hibernate performs dirty checking during flush.
  6. The session is cleared or closed and its first-level cache is discarded.
try (Session session = sessionFactory.openSession()) {
    Employee employee = session.find(Employee.class, 101L);
    employee.setName("Updated name");

    // Hibernate detects the change during flush or commit.
    session.flush();
}

Managing the Persistence Context

MethodEffect
session.clear()Detaches all managed entities and empties the session cache.
session.evict(entity)Detaches one entity from the persistence context.
session.refresh(entity)Reloads the entity state from the database and discards its in-memory changes.
session.detach(entity)JPA-style operation that detaches one entity where supported.
session.close()Closes the session and discards its first-level cache.
Employee employee = session.find(Employee.class, 101L);
session.evict(employee);

// The entity is no longer managed by this session.
Employee reloaded = session.find(Employee.class, 101L);

Large Loops and Batch Processing

The first-level cache grows as entities become managed. In a large import, periodically flush changes and clear the session to control memory usage.

for (int index = 1; index <= 1_000; index++) {
    session.persist(new Employee("Employee " + index));

    if (index % 50 == 0) {
        session.flush();
        session.clear();
    }
}

After clear(), previously managed objects become detached. Do not assume that references still point to managed entities; reattach or reload objects when the next operation requires management.

First-Level versus Second-Level Cache

CharacteristicFirst-level cacheSecond-level cache
ScopeOne SessionShared across sessions in a SessionFactory
DefaultEnabled automaticallyOptional and requires configuration
LifetimeSession or persistence-context lifetimeProvider and SessionFactory lifetime
PurposeIdentity consistency and avoiding repeated work in one unit of workReducing database reads across sessions

The first-level cache is not a replacement for a second-level cache. Use a second-level cache only after measuring access patterns, invalidation requirements, memory usage, and data staleness tolerance.

Entity Lookup versus Query Results

The persistence context primarily guarantees identity for managed entities. A query may still execute SQL each time unless query caching or application-level result reuse is configured. Do not assume that every repeated HQL query is automatically served without SQL.

Employee first = session.find(Employee.class, 101L);

List<Employee> results = session
    .createQuery(
        "from Employee where id = :id",
        Employee.class)
    .setParameter("id", 101L)
    .getResultList();

Best Practices

  • Keep sessions short and aligned with a unit of work.
  • Use one session consistently when repeated entity access should benefit from the first-level cache.
  • Flush and clear during large batch operations.
  • Do not share a session between threads.
  • Remember that clearing the session detaches managed entities.
  • Use SQL logging and measurements before optimizing cache behavior.
  • Be careful with stale data when adding a second-level cache.
Summary: Hibernate's first-level cache is the session's persistence context. It is automatic, session-scoped, and can prevent repeated entity loads within the same unit of work.