공부하기/Spring

[Spring] JPA Cascade에 대해 정리해보자 💭

다섯자두 2025. 3. 11. 17:28

JPA Cascade란?

  • 부모 엔티티가 수행하는 특정 영속성 작업(persist, merge, remove, refresh, detach)을 연관된 자식 엔티티에도 전파하는 기능이다.

예를 들어 Order - OrderItem의 관계, Post - Comment의 관계를 생각하면 된다.

Order가 삭제된다면 해당 OrderItem 데이터는 남아있을 필요가 없으므로 삭제되어야 한다.

Post - Comment 역시 동일하다.

@Entity
public class Order {
    @Id @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "order")
    private List<OrderItem> orderItems = new ArrayList<>();

    public void addOrderItem(OrderItem item) {
        orderItems.add(item);
        item.setOrder(this);
    }
}

@Entity
public class OrderItem {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;

    public void setOrder(Order order) {
        this.order = order;
    }
}

이런 경우 Order가 삭제될 때 해당 Order의 OrderItem들을 찾아서 직접 삭제 처리해주어야 한다.

orderItemRepository.deleteByOrderId(orderId);
orderRepository.deleteById(orderId);

 

Order가 생성될 때 OrderItem은 함께 생성되고, Order가 삭제될 때 OrderItem은 함께 삭제된다.

이처럼 생명주기가 같은 두 엔티티가 있을 때, 한 엔티티에서 특정 작업이 일어나면 연관된 엔티티에도 해당 작업이 적용될 수 있도록 자동화해주는 것이 JPA Cascade 기능이다.

 

Cascade 적용 방법

연관 관계 매핑(@OneToOne, @OneToMany, @ManyToOne, @ManyToMany)에서 사용할 수 있으며, cascade 속성을 설정하여 적용할 수 있다.

@Entity
public class Order {

// ... 기타

    @OneToMany(mappedBy = "order", cascade = CascadeType.타입명시)
    private List<OrderItem> orderItems = new ArrayList<>();

}

 

Cascade에 지정 가능한 Type들

1. PERSIST

엔티티를 영속화할 때 연관 엔티티도 함께 영속화한다.

@Entity
public class Order {

// ... 기타

    @OneToMany(mappedBy = "order", cascade = CascadeType.PERSIST)
    private List<OrderItem> orderItems = new ArrayList<>();

    public void addOrderItem(OrderItem item) {
        orderItems.add(item);
        item.setOrder(this);
    }
}
// 예시 코드

Order order = new Order();
OrderItem item1 = new OrderItem();
OrderItem item2 = new OrderItem();

order.addOrderItem(item1);
order.addOrderItem(item2);

entityManager.persist(order); // OrderItem에 대한 insert 쿼리도 함께 작성됨

2. REMOVE

엔티티를 삭제할 때 연관 엔티티도 함께 삭제한다.

// Order 클래스

@OneToMany(mappedBy = "order", cascade = CascadeType.REMOVE)
private List<OrderItem> orderItems = new ArrayList<>();
// 예시 코드
Order order = entityManager.find(Order.class, orderId);
entityManager.remove(order); // OrderItem에 대한 delete 쿼리도 함께 작성됨

3. MERGE

엔티티를 수정할 때, 연관 엔티티도 변경사항이 있으면 함께 수정된다.

// Order 클래스

@OneToMany(mappedBy = "order", cascade = CascadeType.MERGE)
private List<OrderItem> orderItems = new ArrayList<>();
Order order = entityManager.find(Order.class, orderId);
order.setSomeField("Updated Data");

OrderItem item = order.getOrderItems().get(0);
item.setSomeField("Updated Data");

entityManager.merge(order); // OrderItem에 대한 update 쿼리도 함께 작성된다.

3. REFRESH

엔티티에 대한 최신 데이터를 DB에서 가져올 때, 연관된 엔티티도 함께 새로고침된다.

4. DETACH

엔티티를 영속성 컨텍스트에서 제거할 때, 관련 엔티티도 함께 제거한다. (데이터베이스에 제거하는 것이 아님에 유의)

5. ALL

위의 사항을 모두 적용한다. 즉 모든 생명주기를 함께 하도록 한다.

 

CascadeType.ALL과 함께 사용되는 OrphanRemoval

많은 블로그들에서 `CascadeType.ALL`과 함께 `OrphanRemoval = true`를 함께 선언하고 있는 것을 확인할 수 있다.

OrphanRemoval 기능

`@OneToMany` 또는`@OneToOne`의 연관 관계에서 사용할 수 있다.

Order - OrderItem 처럼 OneToMany 관계에서 부모 객체는 List로 자식 객체들을 가진다.

이 때, 부모 객체에서 List에 접근하여 요소를 삭제하면, 해당 요소가 실제 delete 처리가 되도록 하는 것이 OrphanRemoval 기능이다.

즉, 부모 객체로부터 제거된 자식 객체를 자동으로 DB에서도 삭제되도록 한다.

☑️ CascadeType.ALL과 OrphanRemoval = true를 함께 사용하면

  • 부모 객체와 함께 자식 객체는 persist(), merge(), remove() 등 모든 영속성 전이를 받는다.
  • 부모 객체를 삭제하지 않더라도, 부모 객체의 List에서 제거된 자식 객체를 자동으로 삭제한다.

즉, 부모 객체가 자식 객체의 생명주기를 완전히 제어할 수 있게 된다.

 

Cascade는 모든 연관관계 매핑에서 사용할 수 있을까?

  • 이론적으로 모든 연관관계 매핑에서 사용할 수 있다.
  • 다만 논리적으로 cascade 적용이 추천되지 않고 사용하지 않는 연관관계가 존재한다.

예를 들어, `@ManyToOne` 관계에서 Cascade는 대부분 불필요하거나 위험한 경우가 많다.

@Entity
public class OrderItem {
    @ManyToOne // ❌ Cascade 적용 비추천
    @JoinColumn(name = "order_id")
    private Order order;
}

근데 그냥 생각해봐도 OrderItem이 하나 삭제되는데 Order도 함께 삭제된다? 비정상적인 로직이다..

Comment가 삭제되는데 Post도 삭제된다? 역시 비정상적이다.

특정 부모 엔티티를 구성하는 개별 엔티티가 변경되거나 삭제된다고 해서 부모 엔티티가 함께 변경되는 일은 거의 없기 마련이다.

두 관계의 방향성을 잘 생각해보고 사용하는 것이 중요할 것 같다.

결론

JPA의 모든 연관 관계 매핑에서 Cascade를 사용할 수 있다.

그렇지만 모든 경우에 적절한 것은 아니며, 부모-자식 간 생명주기가 강하게 결합된 경우에만 적용하는 것이 적절하다.

  • 이 관계에서 부모와 자식이 정말 함께 관리되어야 하는가?
  • 두 엔티티간 작업의 연동이 비즈니스적으로 타당한가?

의 질문에 답을 고민한 후, Cascade를 적용하여야겠다.

 

Reference

https://tecoble.techcourse.co.kr/post/2023-08-14-JPA-Cascade/

https://www.baeldung.com/jpa-cascade-types