Когда сущности записываются в Persistence Context в JPA/Hibernate?

«Когда сущности записываются в Persistence Context в JPA/Hibernate?» — вопрос из категории Hibernate, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Persistence Context (контекст持久化) — это набор управляемых (managed) сущностей, за которыми Hibernate отслеживает изменения для последующей синхронизации с БД. Сущности попадают в контекст в нескольких случаях:

1. При вызове EntityManager.persist(entity): Сущность переходит из состояния transient (новый, не связанный с контекстом) в managed. Она будет сохранена в БД при следующей синхронизации (flush).

2. При загрузке из БД (EntityManager.find(), createQuery(...).getResultList()): Загруженные сущности сразу находятся в состоянии managed.

3. При вызове EntityManager.merge(entity) для detached-сущности: Создается управляемая копия detached-объекта, изменения которой будут сохранены.

4. При вызове EntityManager.refresh(entity): Состояние управляемой сущности перезагружается из БД.

Жизненный цикл сущности и контекст:

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

// 1. PERSIST - добавление новой сущности в контекст
User newUser = new User("Alice"); // TRANSIENT
em.persist(newUser);              // Теперь MANAGED

// 2. FIND - загрузка сущности в контекст
User managedUser = em.find(User.class, 1L); // MANAGED
managedUser.setName("Bob"); // Изменение отслеживается!

// 3. MERGE - повторное присоединение detached-сущности
User detachedUser = new User(2L, "Charlie"); // DETACHED
User reattachedUser = em.merge(detachedUser); // Возвращает MANAGED копию

// Синхронизация с БД происходит при:
// - em.flush() (явный вызов)
// - em.getTransaction().commit() (автоматический flush перед commit)
// - Выполнении запроса, использующего измененные данные

em.getTransaction().commit(); // FLUSH + COMMIT -> запись в БД
em.close();

Ключевой момент: Изменения управляемых (managed) сущностей автоматически отслеживаются и записываются в БД при операции flush, которая обычно происходит перед commit транзакции.