Learn how delete cascading works in Hibernate and Spring Boot, including CascadeType.REMOVE, orphanRemoval, MySQL foreign keys, and safe deletion practices.
Updated August 2026 — full tutorial restored for this URL.
TL;DR
-
Hibernate and MySQL can both cascade deletes, but they operate at different layers and should be understood separately.
-
CascadeType.REMOVEdeletes managed child entities when their parent is deleted. -
orphanRemoval = truedeletes a child when it is removed from the parent’s collection. -
MySQL
ON DELETE CASCADElets the database automatically remove child rows when the parent is deleted. -
Use cascades carefully. Avoid unnecessary
CascadeType.ALL, test destructive operations, and consider soft deletes when data must be retained.
In this tutorial I explain how delete cascade works in Hibernate / Spring Data JPA, how it maps to MySQL foreign keys, and how to avoid accidentally wiping child rows.
Related: JPA Auditing in Spring Boot.
- Cascade vs database ON DELETE CASCADE
- CascadeType options that matter for delete
- Parent/child example (Order → OrderLine)
- orphanRemoval
- MySQL FK strategy
- Safe delete checklist
1. Cascade vs database ON DELETE CASCADE
Two different layers can delete children:
- JPA cascade — Hibernate issues extra DELETE/UPDATE SQL when you call
repository.delete(parent)or change the collection. - Database FK —
ON DELETE CASCADEon the foreign key makes MySQL delete children when the parent row is removed, even outside JPA.
Prefer understanding both. Relying on only one can surprise you in batch jobs or native SQL.
2. CascadeType options that matter for delete
CascadeType.REMOVE/ALL— deleting parent deletes managed children.CascadeType.PERSIST/MERGE— not about delete; do not confuse them.orphanRemoval = true— removing a child from the collection deletes that child row.
3. Parent/child example (Order → OrderLine)
@Entity
public class OrderEntity {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderLine> lines = new ArrayList<>();
public void addLine(OrderLine line) {
lines.add(line);
line.setOrder(this);
}
}
@Entity
public class OrderLine {
@Id @GeneratedValue
private Long id;
@ManyToOne(optional = false)
private OrderEntity order;
}
Deleting the order with orderRepository.delete(order) removes lines when cascade includes REMOVE (or ALL). Always keep both sides of the association in sync (addLine helper).
4. orphanRemoval
order.getLines().remove(line); // with orphanRemoval=true → DELETE line
orderRepository.save(order);
Use orphanRemoval for true composition (line cannot exist without order). Avoid it for shared references (e.g. many-to-many tags).
5. MySQL FK strategy
CONSTRAINT fk_line_order FOREIGN KEY (order_id)
REFERENCES orders(id) ON DELETE CASCADE
If JPA and MySQL both cascade, deletes still work but logs get noisier. For soft-delete apps, use neither hard cascade — mark deleted_at instead.
6. Safe delete checklist
- Do not put
CascadeType.ALLon every association “just in case”. - Test delete in a transaction and inspect SQL (
spring.jpa.show-sql=true). - For large graphs, prefer explicit service methods over deep cascades.
- Never cascade remove from child → parent.
Final Thoughts
Delete cascades can make entity relationships much easier to manage, but they also make destructive operations easier to trigger. The important distinction is knowing whether Hibernate or the database is responsible for removing the child records.
For tightly coupled parent-child relationships, options such as CascadeType.REMOVE and orphanRemoval can simplify persistence logic. But they should not be applied indiscriminately, especially where entities are shared or where deleting a parent could remove more data than intended.
Before using cascading deletes in production, understand the relationship, test the generated SQL, and decide deliberately whether hard deletion or soft deletion is appropriate for your application.