Gymterview
middle

Жизненный цикл Entity в Hibernate

Сущность (Entity) в Hibernate проходит через четыре состояния в рамках Persistence Context.

Аналогия из жизни: представьте отдел кадров. Transient — человек, о котором отдел кадров ничего не знает. Persistent — оформленный сотрудник, за которым ведётся наблюдение. Detached — уволившийся, но его личное дело осталось в архиве. Removed — дело помечено на удаление из архива.

Четыре состояния

  1. Transient (Новый) — объект создан через new, не связан с Persistence Context и не имеет представления в БД:
Пример
User user = new User("John", "john@example.com"); // Transient
// Hibernate ничего не знает об этом объекте
  1. Persistent (Управляемый) — объект связан с Persistence Context и имеет представление в БД. Все изменения автоматически синхронизируются с БД при flush/commit:
Пример
session.persist(user);              // Transient → Persistent
User found = session.find(User.class, 1L); // Persistent (загружен из БД)

found.setName("Jane");              // изменение автоматически попадёт в БД (Dirty Checking)
  1. Detached (Отсоединённый) — объект имеет представление в БД, но не связан с текущим Persistence Context:
Пример
session.close();                    // все сущности → Detached
session.detach(user);               // конкретная сущность → Detached
session.evict(user);                // Hibernate API — то же самое

// Detached объект можно вернуть в Persistent:
session.merge(user);                // Detached → Persistent (копирование состояния)
  1. Removed (Удалённый) — объект помечен для удаления, будет удалён из БД при flush/commit:
Пример
session.remove(user);               // Persistent → Removed
// DELETE будет выполнен при flush/commit

Диаграмма переходов

Пример
         new()          persist()
[Нет] ────────→ [Transient] ────────→ [Persistent] ←──── find()/load()/query
                     │                    │   ↑
                     │              detach()/  merge()
                     │              close()    │
                     │                    ↓   │
                     │              [Detached]
                     │                    │
                     │                remove()
                     │                    ↓
                     └──────────→ [Removed] ────→ DELETE в БД

Важное

  • Persistent — единственное состояние, в котором Hibernate отслеживает изменения
  • persist() — Transient → Persistent, merge() — Detached → Persistent (копия), remove() — Persistent → Removed
  • Dirty Checking работает только для Persistent-объектов: изменение поля автоматически генерирует UPDATE
  • Persistence Context гарантирует identity: session.find(User.class, 1L) == session.find(User.class, 1L)true

Частые ошибки

  • Путать persist() и merge() — persist делает объект managed, merge создаёт managed копию (оригинал остаётся detached)
  • Изменять Detached-объект и ожидать UPDATE — изменения detached-объекта не отслеживаются; нужен merge()
  • Вызывать persist() для объекта с заданным @Id — если @GeneratedValue не используется, нужен merge()
  • Не понимать flush — persist() не выполняет INSERT немедленно; SQL выполняется при flush (commit, query, session.flush())

Как используется в 2026

  • Spring Data JPA скрывает управление состояниями за save(), findById(), delete()
  • save() в Spring Data вызывает persist() для нового объекта или merge() для существующего
  • Понимание жизненного цикла необходимо для отладки — без него невозможно объяснить, почему UPDATE не выполнился или выполнился лишний раз

На собеседовании: рисуйте диаграмму четырёх состояний и переходов между ними. Интервьюер ожидает, что вы знаете: Transient → persist() → Persistent, Persistent → detach()/close() → Detached, Detached → merge() → Persistent. Частый уточняющий вопрос — «чем persist отличается от merge?».