middle
Жизненный цикл Entity в Hibernate
Сущность (Entity) в Hibernate проходит через четыре состояния в рамках Persistence Context.
Аналогия из жизни: представьте отдел кадров. Transient — человек, о котором отдел кадров ничего не знает. Persistent — оформленный сотрудник, за которым ведётся наблюдение. Detached — уволившийся, но его личное дело осталось в архиве. Removed — дело помечено на удаление из архива.
Четыре состояния
- Transient (Новый) — объект создан через
new, не связан с Persistence Context и не имеет представления в БД:
Пример
User user = new User("John", "john@example.com"); // Transient
// Hibernate ничего не знает об этом объекте
- Persistent (Управляемый) — объект связан с Persistence Context и имеет представление в БД. Все изменения автоматически синхронизируются с БД при flush/commit:
Пример
session.persist(user); // Transient → Persistent
User found = session.find(User.class, 1L); // Persistent (загружен из БД)
found.setName("Jane"); // изменение автоматически попадёт в БД (Dirty Checking)
- Detached (Отсоединённый) — объект имеет представление в БД, но не связан с текущим Persistence Context:
Пример
session.close(); // все сущности → Detached
session.detach(user); // конкретная сущность → Detached
session.evict(user); // Hibernate API — то же самое
// Detached объект можно вернуть в Persistent:
session.merge(user); // Detached → Persistent (копирование состояния)
- 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?».