Stage 9: JDBC, JPA and Hibernate, lesson 4 of 6

Persistence context and entity states

Advanced3 min read@since 17Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

The persistence context (the first-level cache) is a map of entities managed by an EntityManager, usually one per transaction.

Entity states:

  • Transient: new Course(), unknown to JPA.
  • Managed: persisted or loaded inside the context; changes are tracked.
  • Detached: the context has closed (the transaction ended); changes are no longer tracked.
  • Removed: scheduled for deletion.

Dirty checking: at flush time Hibernate compares managed entities with the snapshot taken when they were loaded and issues UPDATEs automatically. You don't need save() after changing a managed entity.

Inside one context, loading the same id twice returns the same object and hits the database only once.

Example

Java
@Transactional
public void rename(Long id, String title) {
    Course c = courseRepository.findById(id).orElseThrow();   // managed
    c.setTitle(title);                                         // no save() needed
}   // commit: flush, dirty check, then UPDATE course SET title = ? ...

@Transactional
public void identity(Long id) {
    Course a = em.find(Course.class, id);
    Course b = em.find(Course.class, id);
    System.out.println(a == b);          // true: first-level cache, one SELECT
}

Course detached = service.load(id);    // that transaction has ended
detached.setTitle("New title");        // not saved automatically
Course merged = em.merge(detached);    // copies state onto a managed instance

Common mistake

Loading 100,000 entities in one transaction. The persistence context keeps all of them plus their snapshots and memory explodes. Page or stream instead, and call clear() periodically in batch jobs.

Under the hood

A flush happens before commit, before a JPQL query that touches affected tables (AUTO flush mode), or when you call em.flush(). LazyInitializationException means you touched a lazy association on a detached entity. Fix it with a fetch join, an entity graph or a DTO projection, not with Open Session in View; Spring Boot enables spring.jpa.open-in-view by default and logs a warning, so set it to false. The optional second-level cache is shared across sessions.

Check yourself

You change a field of a managed entity inside @Transactional without calling save(). What happens?

How this connects

Part of Job-ready backend developer.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.