Жизненный цикл 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.
Переходы
| Из | Операция | В |
|---|---|---|
| transient | persist | managed |
| managed | detach, clear, закрытие контекста | detached |
| detached | merge | исходный остаётся detached, возвращается managed-копия |
| managed | remove | removed |
| removed | rollback | состояние зависит от нового контекста; объект нельзя считать надёжно managed |
id != null не доказывает, что сущность detached: ключ можно назначить вручную transient-объекту. И наоборот, при некоторых генераторах managed-объект получает ключ только во время вставки.
Типичные сбои
- передали detached-объект в
persist; - изменили detached-сущность и ожидали автоматический
UPDATE; - проигнорировали результат
merge; - сериализатор коснулся lazy-связи после закрытия контекста;
- удалили родителя с чрезмерным
cascade.
Вопросы для повторения
- Как понять, что объект managed?
EntityManager.contains(entity)в конкретном контексте. - Detached равен transient? Нет: detached обычно соответствует существующей строке и имеет идентификатор.
- Что происходит с объектом после commit? Зависит от области контекста; при закрытии он становится detached.
- Почему
mergeвозвращает другой объект? JPA копирует состояние в экземпляр, принадлежащий текущему контексту.
Связано: EntityManager, Hibernate, Fetch type Hibernate.