I ran into a subtle issue the other day while working on a Spring Boot project, and it reminded me how easy it is to confuse @OnDelete(action = OnDeleteAction.CASCADE)
with CascadeType.REMOVE
. If you're using JPA and Hibernate and trying to cascade deletes between entities, you've probably seen both. They seem to do the same thing - but they don’t.
CascadeType.REMOVE: JPA-Level Cascade
Let’s start with the more familiar one: CascadeType.REMOVE
. This is part of standard JPA. When you annotate a relationship like this:
@OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE)
private List<Comment> comments;
it means: “When I delete the parent entity (in this case, Post), go ahead and also delete the child entities (Comments).”
But here’s the catch: JPA does this in Java, not in the database. That means it will:
- Load all the child entities into memory
- Delete them one by one using separate SQL DELETE statements
If you have only a few children, that’s fine. But if your Post
has 1,000+ Comments
? Now we’re talking potential performance issues. I've seen apps hit OutOfMemoryErrors from this when dealing with massive datasets.
@OnDelete(action = OnDeleteAction.CASCADE): Let the DB Handle It
This one’s a Hibernate-specific feature. You use it on the child side of the relationship:
@ManyToOne
@JoinColumn(name = "post_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private Post post;
It tells Hibernate: “Don’t bother deleting this entity in Java — let the database take care of it using a foreign key with ON DELETE CASCADE.”
So when you delete a Post
, the database itself will automatically remove the related Comments
- no fetching, no iteration, no extra DELETEs. It’s much faster and more efficient.
Note:
@OnDelete
is a Hibernate-specific annotation and not part of standard JPA. If you switch to another JPA provider, it may not work.
So Which One Should You Use?
Use CascadeType.REMOVE
if:
You’re dealing with a small number of child entities — the overhead of loading and deleting them in memory isn’t a big deal.
You want your code to be JPA-compliant and database-independent — maybe you’re targeting multiple databases or just don’t want to rely on DB-specific features.
You don’t control the schema, or you’re not sure if the database supports ON DELETE CASCADE — or you just want to avoid modifying foreign key constraints.
Use @OnDelete(CASCADE)
if:
- You expect lots of related data — hundreds or thousands of rows, for example.
- You care about performance and want to avoid loading child entities into memory just to delete them.
- You’re using Hibernate and you’re comfortable tweaking the database schema — this approach depends on having the right ON DELETE CASCADE setup in your DB.
This article focuses on common use cases in JPA and Hibernate based on real-world experience. There are deeper edge cases I’ve left out for clarity. Feedback welcome!
Top comments (0)