middle
Как маппить связи между сущностями? В чём разница между LAZY и EAGER загрузкой?
JPA поддерживает четыре типа связей: @ManyToOne, @OneToMany, @ManyToMany, @OneToOne.
Значения по умолчанию (важно знать!)
| Аннотация | FetchType по умолчанию |
|---|---|
@ManyToOne |
EAGER (это плохо!) |
@OneToOne |
EAGER (это плохо!) |
@OneToMany |
LAZY (это хорошо) |
@ManyToMany |
LAZY (это хорошо) |
Рекомендация: всегда явно указывайте fetch = FetchType.LAZY для всех связей.
@ManyToOne / @OneToMany
Пример
@Entity
public class Order {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
@Entity
public class User {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Order> orders = new ArrayList<>();
public void addOrder(Order order) {
orders.add(order);
order.setUser(this);
}
}
LAZY vs EAGER
| Тип | Когда загружается | Когда использовать |
|---|---|---|
| LAZY | При первом обращении к коллекции/полю | По умолчанию для всех связей |
| EAGER | Сразу вместе с родительской сущностью | Почти никогда |
CascadeType
| CascadeType | Описание |
|---|---|
| PERSIST | Каскадное сохранение |
| MERGE | Каскадное обновление |
| REMOVE | Каскадное удаление |
| ALL | Все вышеперечисленные |
На собеседовании: ключевое – знать значения FetchType по умолчанию и всегда ставить LAZY. Частая ошибка – оставлять EAGER по умолчанию для
@ManyToOne(причина проблемы N+1) или использоватьCascadeType.ALLбез необходимости.