FetchType, Cascade, состояния entity
FetchType решает, когда подгружать связанные данные — сразу вместе с основным объектом или только по требованию:
@OneToMany(fetch = FetchType.LAZY) // подгрузить orders, только когда реально обратишься к ним
private List<Order> orders;
@ManyToOne(fetch = FetchType.EAGER) // подгрузить user сразу вместе с Order
private User user;
Cascade решает, что делать со связанными объектами при операции над главным, например — удалять ли заказы, если удалили пользователя:
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders;
// userRepository.delete(user) автоматически удалит и все его orders
Копнуть глубже
По умолчанию: @ManyToOne/@OneToOne — EAGER, @OneToMany/@ManyToMany — LAZY. Это сделано из соображений производительности: подгружать “много” объектов сразу для каждого запроса — дорого (см. тему «Проблема N+1»), поэтому списки по умолчанию ленивые.
Состояния Entity (жизненный цикл объекта в Hibernate):
| Состояние | Что значит |
|---|---|
| Transient | объект только что создан через new, Hibernate о нём не знает |
| Managed (Persistent) | объект отслеживается Hibernate, изменения автоматически синхронизируются с БД |
| Detached | объект больше не отслеживается (например, сессия закрылась), изменения не сохраняются сами |
| Removed | помечен на удаление, будет удалён при коммите |
Главная ловушка с Detached — попытка обратиться к ленивой (LAZY) связи у объекта в состоянии Detached приводит к LazyInitializationException (подробный разбор — отдельная тема «LazyInitializationException»).
• четыре состояния entity и чем опасен Detached (если дошёл до 2-го слоя).