본문 바로가기
Backend/JPA

JPA - 영속성 전이(CASCADE)와 고아 객체(부모 엔티티를 통해 자식의 생명주기 관리)

by 개발자-제이 2025. 2. 24.

 

1. 영속성 전이(CASCADE)란?

JPA에서 영속성 전이(Cascade)는 특정 엔티티를 영속 상태로 만들 때, 연관된 엔티티도 함께 영속 상태로 만드는 기능을 의미한다.

  • 주로 부모-자식 관계에서 부모를 저장하면 자식도 자동으로 저장되도록 할 때 사용한다.

영속성 전이가 필요한 이유

  • 부모 엔티티와 자식 엔티티를 함께 관리할 때 편리
  • 연관된 엔티티의 생명주기를 일관되게 관리 가능
  • 중복된 persist(), remove() 호출을 줄여 코드 간결화 가능

영속성 전이 예제

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;
    
    @OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
    private List<Child> children = new ArrayList<>();
    
    public void addChild(Child child) {
        children.add(child);
        child.setParent(this);
    }
}

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

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}
Parent parent = new Parent();
Child child1 = new Child();
Child child2 = new Child();

parent.addChild(child1);
parent.addChild(child2);

em.persist(parent); // parent만 persist 해도 child1, child2도 함께 영속화됨
  • CascadeType.PERSIST 덕분에 parent를 persist() 할 때 child1, child2도 자동으로 저장된다.
  • 만약 CASCADE 설정이 없다면, em.persist(child1), em.persist(child2)를 따로 호출해야 한다.

 

2. CASCADE의 종류

 

옵션 설명
ALL 모든 영속성 전이 적용
PERSIST 부모가 persist() 될 때 자식도 함께 persist()
REMOVE 부모가 remove() 될 때 자식도 함께 삭제
MERGE 부모가 merge() 될 때 자식도 함께 merge()
REFRESH 부모가 refresh() 될 때 자식도 함께 refresh()
DETACH 부모가 detach() 될 때 자식도 함께 detach()
  • 실무에서는 ALL, PERSIST, REMOVE가 주로 사용된다.

 

3. 고아 객체 제거

JPA에서는 부모-자식 관계에서 부모와의 연관 관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능을 제공하는데, 이를 고아 객체 제거(Orphan Removal)라고 한다.

 * orphanRemoval = true 옵션을 사용하면 부모 객체에서 자식 객체를 remove() 하면, 자동으로 삭제된다.

고아 객체 제거 예제

@Entity
public class Parent {
    @Id @GeneratedValue
    private Long id;
    
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Child> children = new ArrayList<>();
    
    public void removeChild(Child child) {
        children.remove(child);
        child.setParent(null);
    }
}

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

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}
  • 부모 객체에서 children.remove(child)를 하면, 자식 객체는 자동으로 DELETE 쿼리 실행됨

고아 객체 제거 주의점

  • 참조하는 곳이 하나일 때만 사용해야 한다.
  • 부모 엔티티를 삭제하면, 자식도 자동으로 삭제됨 (CascadeType.REMOVE와 동일한 효과)
  • @OneToOne, @OneToMany 관계에서만 사용 가능

 

4. 영속성 전이와 고아 객체 제거를 함께 사용할 때

CascadeType.ALL + orphanRemoval = true를 함께 사용하면, 부모 엔티티를 통해 자식 엔티티의 생명주기를 완전히 관리할 수 있다.

@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> children = new ArrayList<>();
  • 부모를 persist() 하면 자식도 자동 저장
  • 부모를 remove() 하면 자식도 자동 삭제
  • 부모에서 자식을 remove() 하면 자동으로 DELETE

 언제 사용하면 좋을까?

  • 부모 엔티티가 자식을 독점 관리할 때
  • 도메인 주도 설계(DDD)에서 Aggregate Root 개념을 적용할 때

 

5. 활용 사례

회원과 주문 관계에서 활용

@Entity
public class Member {
    @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Order> orders = new ArrayList<>();
}
  • 회원이 주문을 삭제하면, 주문도 자동으로 삭제

게시글과 댓글 관계에서 활용

@Entity
public class Post {
    @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Comment> comments = new ArrayList<>();
}
  • 게시글이 삭제되면, 연관된 댓글도 자동 삭제

 

6. 정리

❗영속성 전이(CASCADE): 부모 엔티티를 persist() 할 때 자식도 함께 persist()
고아 객체 제거: 부모와의 연관 관계가 끊어진 자식 객체를 자동으로 삭제
CascadeType.ALL + orphanRemoval = true: 부모 엔티티를 통해 자식의 생명주기 완전 관리
실무에서는 부모가 자식을 완전히 소유할 때만 사용해야 한다.

반응형