본문 바로가기
데이터베이스/JPA

[JPA] Cascade(영속성 전이), OrphanRemoval(고아객체 제거)

by jeonghaemin 2021. 3. 17.
728x90

cascade : 영속성 전이

  • JPA에서 Cascade 옵션을 사용하면 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들 수 있다.
  • 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공한다.
@Entity
public class Parent {

    @Id 
        @GeneratedValue
    private Long id;

        //cascade 옵션 적용
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    private List<Child> childList = new ArrayList<>();

    public List<Child> getChildList() {
        return childList;
    }

    public Long getId() {
        return id;
    }
}

@Entity
public class Child {

        @Id
    @GeneratedValue
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Parent parent;

    protected Child() {

    }

    public Child(Parent parent) {
        this.parent = parent;
    }
}

Parent엔티티의 childList를 보면 cascade 옵션이 적용되어있는 것을 볼 수 있다. 이렇게 되면 parent만 영속화하여도 cascade 옵션으로 인해 영속성 전이가 일어나 childList에 저장되어 있는 Child 엔티티들도 영속화가 된다.

Parent parent = new Parent();

Child child1 = new Child(parent);
Child child2 = new Child(parent);

parent.getChildList().add(child1);
parent.getChildList().add(child2);

em.persist(parent);

위와 같이 parent에 대해서만 persist 메서드를 호출하였음에도 불구하고, child 들도 insert 쿼리가 나가는 것을 볼 수 있다.

Hibernate: 
    /* insert hello.Parent */ 
insert into Parent(id) values (?)

Hibernate: 
    /* insert hello.Child */ 
insert into Child (parent_id, id) values (?, ?)

Hibernate: 
    /* insert hello.Child */ 
insert into Child (parent_id, id) values (?, ?)

cascade 옵션에 넣을 수 있는 값들은 다음과 같다.

  • ALL : 모두 적용
  • PERSIST : 영속
  • REMOVE : 삭제
  • MERGE : 병합
  • REFRESH
  • DETACH : 준영속

이 값들의 의미는 다음과 같다. EntityManager.XX 메서드를 실행했을 때 연관된 엔티티의 cascade 옵션에 XX 값이 적용되어 있다면 해당 옵션이 적용된 엔티티도 같이 XX 작업을 하겠다는 뜻이다.

예를 들어 A라는 특정 엔티티와 연관된 B라는 엔티티의 cascade 옵션이 PERSIST로 적용되어 있다면, A 엔티티를 대상으로 EntityManager.persist(A)가 호출될 때 B도 같이 EntityManager.persist(B)가 호출되는 것이다.

cascade 옵션은 부모 엔티티가 단일 소유자일 때, 부모와 자식의 라이프 사이클이 유사할 때 사용하는 것이 좋다.

orphanRemoval : 고아 객체 제거

orpahnRemoval 옵션을 사용해서 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하도록 할 수 있다.

  • 특정 엔티티가 단일 소유할 때, 참조하는 곳이 하나일 때 사용
  • @OneToOne, @OneToMany만 사용 가능
  • 추가적으로 부모를 제거할 때 자식도 같이 제거된다.(CascadeType.REMOVE와 유사)
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();

orphanRemoval = true 를 설정하고 childList에서 Child 객체를 삭제하면 delete 쿼리가 나가는 것을 볼 수 있다.

Parent parent = em.find(Parent.class, parent.getId());
parent.getChildList().remove(0);
Hibernate: 
    /* delete hello.Child */ 
delete from Child where id=?

참고 : 어떤 이유인지는 모르겠지만 orphanRemoval = true 단독으로는 동작하지 않고 cascade = CascadeType.PERSIST 또는 ALL 옵션과 같이 사용해야 동작한다.

영속성 전이 + 고아 객체

  • cascade = ALL과 orphanRemoval = true 옵션을 같이 사용하면 부모 엔티티를 통해서 자식 엔티티의 생명 주기를 관리할 수 있다.
  • 자식 엔티티의 DAO 또는 Repository가 없어도 된다.
  • 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용하다.

참고

댓글