Post

@OnDelete vs JPA Cascade: Persistence Context Consistency Issue

@OnDelete vs JPA Cascade: Persistence Context Consistency Issue

Situation

While migrating the Gift API to JPA at Kakao Tech Campus, there was a requirement to delete options when a product is deleted.

But the entity structure was unidirectional.

1
2
3
4
5
@Entity
public class Option {
    @ManyToOne(fetch = FetchType.LAZY)
    private Product product;  // Only Option → Product reference
}

Product entity had no reference to Option. In this situation, how do you delete associated options when deleting a product?


What Is Persistence Context?

One of the most important concepts in JPA. The persistence context is an environment for persistently storing entities, acting as a first-level cache between the application and database.

Key Features:

  • First-level cache: Within same transaction, querying the same entity returns from cache, not DB
  • Dirty checking: Automatically detects entity changes and reflects to DB on transaction commit
  • Identity guarantee: Same PK in same transaction always returns same instance

Solution 1: @OnDelete (Hibernate)

Used Hibernate’s @OnDelete annotation.

1
2
3
@ManyToOne(fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
private Product product;

This sets ON DELETE CASCADE at DB level, so when a product is deleted, associated options are automatically deleted.


Mentor Feedback

But mentor gave this feedback:

“@OnDelete is Hibernate-specific, and since the DB directly executes cascade delete, it’s not reflected in JPA’s persistence context. This can conflict with JPA consistency.”

Problems:

  • @OnDelete is handled by DB directly
  • JPA’s persistence context doesn’t know about this
  • Accessing deleted entities in the same transaction can cause unexpected behavior

For example, Options are deleted from DB via @OnDelete, but they might still exist in the persistence context, behaving as if they exist.


Solution 2: JPA Cascade (Requires Bidirectional)

Using JPA’s cascade requires bidirectional relationship.

1
2
3
4
5
@Entity
public class Product {
    @OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Option> options = new ArrayList<>();
}

This way JPA manages deletions, maintaining consistency with the persistence context. When Product is deleted, JPA removes associated Options from the persistence context too.


Trade-off

MethodProsCons
@OnDeleteCan keep unidirectional, simple setupInconsistent with JPA persistence context
JPA CascadePersistence context consistency guaranteedRequires bidirectional relationship

Ended up adding bidirectional relationship and using JPA Cascade.


Lessons Learned

  • Hibernate-specific features differ from JPA standard
  • Need to understand difference between DB-level and application-level handling
  • Persistence context consistency is always a concern when using JPA

From Kakao Tech Campus 3rd cohort Gift API clone coding, summarizing mentor feedback.

This post is licensed under CC BY 4.0 by the author.