본문으로 바로가기

[JPA] 영속성 전이(CASCADE)와 고아 객체(orphanRemoval)

category 기타 TIP 2021. 6. 17. 01:11

🎈 영속성 전이는 무엇일까요?

  • 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용하는 옵션입니다.
  • 예) 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장합니다.

  • 부모 저장할 때, em.persist(parent)
  • 연관된 컬렉션안의 자식 엔티티들 모두 다 함께 영속성 컨테스트에 저장하고 싶은 경우
  • 영속성 전이를 하지 않으면 자식 개수만큼 em.persist(child) 일일이 해줘야 번거로움이 있습니다.

영속성 전이 : 저장 예시 (user -> orders 관계)

@OneToMany(mappedBy="parent", cascade = CascadeType.PERSIST)

주의

  • 영속성 전이는 연관관계 매핑하는 것과 아무 관련 없음
  • 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐이다!

 

🎁 CASCADE의 종류

  • ALL : 모두 적용
  • PERSIST : 영속 (저장하여 JPA가 관리하는 상태로, 필요한 시점에 DB에 적용)
  • REMOVE : 삭제 (JPA가 관리는 하나, commit 시점에만 삭제)
  • MERGE : 병합 (연관 관계에 있는 비영속 인스턴스를 영속 인스턴스로 병합)
  • REFRESH : REFRESH
  • DETACH : DETACH (JPA가 관리하지 않는 상태)

참조하는 곳이 한군데인 경우, 하나의 부모만 자식들을 관리하는 경우에만 의미있다. 게시판과 첨부파일과 같은 관계에서만 하는것을 권장합니다.

파일을 여러 엔티티에서 관리한다. 다른 게시물에서도 관리한다하면 사용하면 안됩니다!
parent 하나만 단독으로 관리할 때만 사용해야한다 (소유자가 하나인 경우)

단일 엔티티에 종속적인 경우에 사용! (라이프 사이클이 똑같기 때문)

 

👶 고아 객체 (orphanRemoval)

부모 엔티티와 연관관계가 끊어진 자식 엔티티

  • 고아 객체 제거 : 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제합니다.
  • orphanRemoval = true
  • Parent parent1 = em.find(Parent.class, id);
    parent1.getChildren().remove(0);
    자식 엔티티를 컬렉션에서 제거함 ➡ 부모객체와의 연관관계 끊어짐
  • DELETE FROM CHILD WHERE ID = ? ➡ DELETE 쿼리 발생한다.

주의

  • 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아객체로 보고 삭제하는 기능
  • 참조하는 곳이 하나일 때 사용해야한다!
  • 특정 엔티티가 개인 소유할 때만 사용
  • @OneToMany, @OneToOne만 가능 : 참조하는 쪽이 하나인 경우만 사용

개념적으로 부모를 제거하면 자식은 고아가된다. 따라서 고아 객체 제거기능을 활성화하면, 부모를 제거할 때 자식도 함께 제거된다. 이것은 CascadeType.REMOVE처럼 동작한다.

 

🔥 영속성 전이 + 고아객체 = 생명주기

  • CascadeType.ALL + orphanRemoval=true
  • 스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화, em.remove()로 제거할 수 있습니다.
    • JPA를 통해서 생명주기 관리
  • 두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식 엔티티의 생명주기를 관리할 수 있다.
    • parent와 달리 child는 생명주기를 부모 엔티티가 관리합니다.
    • 굳이 DB로 따지면 DAO나 Repository가 없어도 된다는 의미합니다.
    • 생명주기를 부모가 관리하기 때문입니다.
  • 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용합니다.

 

⚡ orphanRemoval=true  vs  CascadeType.REMOVE

1. Parent가 삭제 되었을 때 Child도 함께 삭제시키는 역할을 수행하는 점에선 동일합니다.

-> 다른점은, 관계를 끊는 것에 대한 응답이 다릅니다.

 

예를 들어, Parent의 Child 값을 null을 주었다고 가정합니다.

 

* orphanRemoval=true는 관계가 끊어진 child를 자동으로 제거 합니다.

* CascadeType.REMOVE는 관계가 끊어진 child를 자동 제거하지 않습니다. 

-> 관계가 끊어졌다는 것을 제거로 보지 않기 때문.

 

정리

1. 부모 엔티티가 삭제되면 자식 엔티티도 삭제된다 => REMOVE

2. 부모 엔티티에서 자식만 삭제하고 싶다 => orphanRemoval = true

 

 

참고사이트 : 김영한의 JPA (인프런)

'기타 TIP' 카테고리의 다른 글

깃허브(github) 잔디심기 안될 때  (0) 2021.09.16
[검색엔진] SOLR 검색엔진에 대해 알아보자.  (0) 2021.06.30
[MSA] Telemetry  (0) 2021.05.25
[MSA] Backing Service  (0) 2021.05.25
[MSA] Service Mesh  (0) 2021.05.25