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

Состояние сущности определяется не заполненностью id, а отношением объекта к текущему Persistence Context.

Состояния

Transient

Обычный новый Java-объект. Контекст его не отслеживает, строка в БД может не существовать.

Invoice invoice = new Invoice();

Managed

Объект прикреплён к контексту. Изменение полей будет обнаружено dirty checking.

em.persist(invoice);
invoice.markPaid();

Detached

Объект раньше был managed, но контекст закрыли, очистили или вызвали detach. Изменения автоматически не сохраняются. Идентификатор при этом обычно остаётся.

Removed

Managed-сущность помечена на удаление. DELETE выполняется при flush.

Переходы

ИзОперацияВ
transientpersistmanaged
manageddetach, clear, закрытие контекстаdetached
detachedmergeисходный остаётся detached, возвращается managed-копия
managedremoveremoved
removedrollbackсостояние зависит от нового контекста; объект нельзя считать надёжно managed

id != null не доказывает, что сущность detached: ключ можно назначить вручную transient-объекту. И наоборот, при некоторых генераторах managed-объект получает ключ только во время вставки.

Типичные сбои

  • передали detached-объект в persist;
  • изменили detached-сущность и ожидали автоматический UPDATE;
  • проигнорировали результат merge;
  • сериализатор коснулся lazy-связи после закрытия контекста;
  • удалили родителя с чрезмерным cascade.

Вопросы для повторения

  1. Как понять, что объект managed? EntityManager.contains(entity) в конкретном контексте.
  2. Detached равен transient? Нет: detached обычно соответствует существующей строке и имеет идентификатор.
  3. Что происходит с объектом после commit? Зависит от области контекста; при закрытии он становится detached.
  4. Почему merge возвращает другой объект? JPA копирует состояние в экземпляр, принадлежащий текущему контексту.

Связано: EntityManager, Hibernate, Fetch type Hibernate.