Cascade Types
IntermediateCascadeType.ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH propagate operations from parent to child; avoid CascadeType.REMOVE on large collections — use bulk queries instead.
Overview
Cascade types determine which `EntityManager` operations on a parent entity are automatically propagated to associated child entities. Without cascading, you must explicitly `persist`, `merge`, or `remove` each child. JPA defines six cascade types: `PERSIST`, `MERGE`, `REMOVE`, `REFRESH`, `DETACH`, and the convenience `ALL` (all six). A common pattern is `cascade = {PERSIST, MERGE}` (equivalently `cascade = ALL` minus `REMOVE`) for owned children where you want lifecycle management but controlled deletion. `orphanRemoval = true` is separate from `CascadeType.REMOVE` and removes children that are no longer referenced in the parent's collection.
The Six Cascade Types
Each type mirrors an `EntityManager` method. `PERSIST` is the most common: saving a new `Order` automatically persists its `OrderItem` children. `MERGE` propagates re-attaching detached graphs. `REMOVE` deletes children when the parent is deleted — dangerous on large collections because Hibernate loads all children first. `REFRESH` and `DETACH` are rarely needed explicitly.
@Entity
public class Order {
@Id @GeneratedValue Long id;
// PERSIST + MERGE: propagate save/update; NOT remove
@OneToMany(mappedBy = "order",
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
orphanRemoval = true)
List<OrderItem> items = new ArrayList<>();
}
// em.persist(order) → also persists all items in the list
Order order = new Order();
order.getItems().add(new OrderItem(order, "SKU-1", 2));
em.persist(order); // items saved automatically
// Remove a single item from the collection
order.getItems().removeIf(i -> i.getSku().equals("SKU-1"));
// orphanRemoval=true → Hibernate fires DELETE for that item on flushCascadeType.REMOVE vs orphanRemoval
`CascadeType.REMOVE` triggers when you call `em.remove(parent)` — it deletes the parent and all its children. `orphanRemoval = true` triggers when a child is removed from the parent's collection (even without deleting the parent). They can be used together or separately. Neither should be used on large collections — Hibernate loads all children into memory before deleting them.
// CascadeType.REMOVE — parent deletion cascades to children
@OneToMany(cascade = CascadeType.REMOVE)
List<Comment> comments;
em.remove(post);
// Hibernate: SELECT * FROM comment WHERE post_id = ? ← loads ALL comments!
// Then: DELETE FROM comment WHERE id = ? (one per comment)
// Then: DELETE FROM post WHERE id = ?
// --- orphanRemoval example ---
@OneToMany(orphanRemoval = true)
List<Address> addresses;
// Remove from collection → child deleted even though parent stays
user.getAddresses().remove(oldAddress);
em.flush(); // DELETE FROM address WHERE id = ?
// --- AVOID on large collections: use bulk delete instead ---
em.createQuery("DELETE FROM Comment c WHERE c.post.id = :postId")
.setParameter("postId", post.getId())
.executeUpdate();
em.remove(em.getReference(Post.class, post.getId()));CascadeType.ALL — Convenience and Pitfalls
`CascadeType.ALL` is shorthand for all six types combined. It is appropriate for **owned, dependent** relationships (like `Order → OrderItem`) where the child has no meaning outside the parent. It is **dangerous** for shared entities — cascading REMOVE on a `@ManyToMany` or a shared reference will delete entities that other parents still reference. Always be explicit about which types you need.
// GOOD: Order owns its items — ALL is safe
@OneToMany(mappedBy = "order",
cascade = CascadeType.ALL, orphanRemoval = true)
List<OrderItem> items;
// DANGEROUS: Tags are shared — CascadeType.ALL would delete the Tag
// from the database when you remove it from a Post's collection
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) // NOT ALL
Set<Tag> tags;
// Rule of thumb:
// Owned, private children → cascade = ALL, orphanRemoval = true
// Shared/referenced entities → cascade = PERSIST, MERGE only
// Large collections → skip cascade REMOVE; use bulk queriesKey Points to Remember
- 1Six cascade types: PERSIST, MERGE, REMOVE, REFRESH, DETACH, ALL (shorthand)
- 2CascadeType.REMOVE loads all children into memory before deleting — avoid on large collections
- 3orphanRemoval removes a child when it's dereferenced from the parent's collection
- 4CascadeType.ALL is safe for private, owned children (OrderItem) but dangerous for shared entities (Tag)
- 5Use PERSIST + MERGE for most parent-child relationships; add orphanRemoval separately if needed
- 6For large collection deletes, always prefer a bulk JPQL/SQL DELETE over cascaded removes
Interview Questions
Sign in to ask AriaWhat is the difference between CascadeType.REMOVE and orphanRemoval=true?
Why should you avoid CascadeType.REMOVE on a collection with thousands of children?
When would you use CascadeType.ALL and when is it dangerous?
Can you use orphanRemoval=true on a @ManyToMany relationship?
What happens if you persist a parent with a new child but forget to add the cascade type?
Ask Aria about Cascade Types
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.