Какие типы Cascade существуют
JPA предоставляет несколько типов каскадных операций, каждый из которых контролирует распространение конкретного типа операции на связанные сущности. Правильный выбор типа casca...
Обзор
JPA предоставляет несколько типов каскадных операций, каждый из которых контролирует распространение конкретного типа операции на связанные сущности. Правильный выбор типа cascade — ключ к корректной работе с графами объектов.
🟢 Junior Level
Все типы CascadeType
CascadeType.ALL — все операции (persist, merge, remove, refresh, detach)
CascadeType.PERSIST — при persist(parent) → persist(child)
CascadeType.MERGE — при merge(parent) → merge(child)
CascadeType.REMOVE — при remove(parent) → remove(child)
CascadeType.REFRESH — при refresh(parent) → refresh(child)
CascadeType.DETACH — при detach(parent) → detach(child)
Пример каждого
// PERSIST — сохранение с children
@OneToMany(cascade = CascadeType.PERSIST)
private List<OrderItem> items;
entityManager.persist(order); // → persist для всех items
// MERGE — обновление с children
@OneToMany(cascade = CascadeType.MERGE)
private List<OrderItem> items;
entityManager.merge(order); // → merge для всех items
// REMOVE — удаление с children
@OneToMany(cascade = CascadeType.REMOVE)
private List<OrderItem> items;
entityManager.remove(order); // → remove для всех items
// ALL — все операции
@OneToMany(cascade = CascadeType.ALL)
private List<OrderItem> items;
Когда НЕ использовать cascade вообще
Не используйте cascade когда обе сущности — aggregate roots с собственным жизненным циклом. Например, Order и Customer — это отдельные агрегаты, каскад между ними опасен.
🟡 Middle Level
Когда что использовать
@OneToMany (composite): CascadeType.ALL + orphanRemoval = true
@ManyToOne: CascadeType.PERSIST, MERGE (или без cascade)
@OneToOne: CascadeType.ALL
@ManyToMany: CascadeType.PERSIST, MERGE
Composite vs Association
// Composite — child не существует без parent
@Entity
public class Order {
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items; // OrderItem без Order не имеет смысла
}
// Association — entities независимы
@Entity
public class Order {
@ManyToOne // no cascade
private User user; // User существует независимо от Order
}
Типичные ошибки
// ❌ Cascade.REMOVE для shared entities
@ManyToOne(cascade = CascadeType.REMOVE)
private User user;
entityManager.remove(order); // ❌ User тоже удалён!
// ❌ Cascade.ALL для @ManyToOne
@ManyToOne(cascade = CascadeType.ALL)
private Category category;
entityManager.remove(product); // ❌ Category удалена!
// ✅ Без cascade для shared
@ManyToOne
private User user; // User управляется отдельно
🔴 Senior Level
Продвинутые сценарии
// Scenario 1: Cascade PERSIST + MERGE для @ManyToOne
@Entity
public class Order {
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
// ⚠️ Code smell: каскад от Order к User — shared entity.
// Может случайно создать дубликаты пользователей.
// Cascade PERSIST/MERGE от дочерней к родительской — антипаттерн.
private User user;
}
// Новый User будет сохранён вместе с Order
User newUser = new User();
Order order = new Order();
order.setUser(newUser);
entityManager.persist(order); // → persist User, persist Order
// Существующий User будет merged
order.setUser(existingUser);
entityManager.merge(order); // → merge User, merge Order
Каскадирование и валидация
@Entity
public class Order {
@Valid // Bean Validation cascade. @Valid — это Hibernate Validator (Hibernate-specific), не JPA-стандарт. Валидация срабатывает при persist/merge.
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> items;
}
// При persist/merge — валидация для всех items
entityManager.persist(order); // → validation для Order + всех items
Production паттерны
// Pattern 1: Order → OrderItem (composite)
@Entity
public class Order {
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items = new ArrayList<>();
public void addItem(OrderItem item) {
items.add(item);
item.setOrder(this);
}
}
// Pattern 2: Order → User (shared)
@Entity
public class Order {
@ManyToOne // no cascade
private User user;
}
// Pattern 3: User → Address (composite)
@Entity
public class User {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Address> addresses = new ArrayList<>();
}
Матрица решений
| Связь | Cascade | orphanRemoval | Почему |
|---|---|---|---|
| @OneToMany (composite) | ALL | true | Child не существует без parent |
| @ManyToOne (shared) | PERSIST, MERGE | false | Entity управляется отдельно |
| @OneToOne (composite) | ALL | true | Один к одному, композиция |
| @ManyToMany | PERSIST, MERGE | false | Shared entities, опасно удалять |
Best Practices
✅ ALL для composite children
✅ PERSIST, MERGE для shared entities
✅ Без REMOVE для shared entities
✅ orphanRemoval для composite children
✅ Матрица решений для каждой связи
❌ REMOVE для shared entities
❌ ALL для @ManyToOne
❌ Cascade.REMOVE в Many-to-Many
❌ Без понимания разницы composite/association
🎯 Шпаргалка для интервью
Обязательно знать:
- 6 типов CascadeType: ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH
- ALL — все операции, но опасен для @ManyToOne и Many-to-Many
- Композиции (Order → OrderItem): CascadeType.ALL + orphanRemoval = true
- Ассоциации (Order → User): PERSIST, MERGE или без cascade
- @ManyToOne с cascade PERSIST/MERGE от дочерней к родительской — антипаттерн (дубликаты)
- Матрица решений: для каждой связи свой cascade, не универсальный
Частые уточняющие вопросы:
- Почему @ManyToOne с cascade — code smell? Каскад от Order к User может создать дубликаты пользователей
- Что такое composite vs association? Composite — child не существует без parent (OrderItem), association — независимые entities (User)
- Можно ли комбинировать cascade? Да: cascade = {CascadeType.PERSIST, CascadeType.MERGE}
- Когда cascade вообще не нужен? Когда entities управляются separately через собственные репозитории
Красные флаги (НЕ говорить):
- «CascadeType.ALL для всех связей» — REMOVE удалит shared entities
- «Cascade.REMOVE для @ManyToOne» — удаление Order удалит User
- «Cascade.ALL для Many-to-Many» — удаление Author удалит все Books
- «Не понимаю разницу composite/association» — критично для выбора cascade
Связанные темы:
- [[20. Как работают каскадные операции (Cascade)]]
- [[22. Что такое orphan removal]]
- [[23. Как правильно использовать @OneToMany и @ManyToOne]]
- [[24. В чём особенности bidirectional relationships]]