개발 일기

[Spring Boot] orphanRemoval = true 고아 객체 관리 본문

Back-End/Spring

[Spring Boot] orphanRemoval = true 고아 객체 관리

개발 일기장 주인 2024. 6. 3. 01:12

전 게시글에서 Cascade 영속성 전이 그리고 그중에서도 ALL, REMOVE, PERSIST 타입에 대해 집중적으로 이해해봤다.

개발하다보면 주로 orphanRemoval=true가 쓰이는 것을 종종 볼 수 있는데 이때 orphanRemoval이 어떤 것을 설정하는 것인지 알아보자.


orphanRemoval = true

부모 엔티티와 연관관계가 끊어진 자식 엔티티 를 자동으로 삭제해주는 설정이다.

Content엔티티에서 Comment와 일대다 관계를 맺을 때 아래와 같이 설정한다고 하자.

// Content 엔티티
@OneToMany(mappedBy = "content", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();

 

아래는 ContentService의 예시 메서드이다.

// ContentService
public void removeCommentFromContent(Long contentId, Long commentId) {
    Content content = contentRepository.findByIdOrThrow(contentId)
    Comment comment = commentRepository.findByIdOrThrow(commentId)

    content.removeComment(comment); // content에서 comment를 제거
}

위와같이 특정 게시글에서 그 게시글의 댓글 중 하나를 제거하기 위해서 부모 - 자식 관계를 끊어 놓게되면 그 결과 Comment 엔티티가 데이터베이스에서 DELETE 되는 것을 확인할 수 있다. 즉, 직접 commandRepository.delete(comment)를 하지 않고 자식 엔티티를 부모 엔티티의 컬렉션에서 제거만 하면 DELETE 쿼리가 나가는 것이다.

즉, 참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능이다.

  • 참조하는 곳이 하나일 때 사용해야하고
  • 특정 엔티티가 개인 소유할 때 사용가능하다.
  • @OneToOne, @OneToMany만 가능한 설정이다.

 

 

CascadeType.REMOVE와 뭔차이?

똑같은 것은 아니다. 단지 특정 상황에 따라 똑같이 동작할 경우가 있을 뿐이다.

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

그렇기 때문에 orphanRemoval = true라는 설정이 부모 객체가 삭제되는 경우 자식이 고아가 되기 때문에 CascadeType.REMOVE처럼 동작는 것이다.

 

 

CascadeType.ALL + orphanRemoval = true

영속성 전이와 고아 객체 관리 기능 두개 모두 동시에 킬 수도 있다.

원래 엔티티는 em.persist()로 영속화, em.remove()로 제거하는 것 처럼 스스로 생명 주기를 관리하게 된다.

그러나 제목처럼 두개의 조건을 모두 활성화하게되면 자식 엔티티가 부모 엔티티를 통해서 생명 주기를 관리할 수 있게 된다.

다른 말로 부모 엔티티를 통해서 자식의 생명 주기가 관리되는 것이다. 그렇게되면 자식 객체는 Repository가 필요없다.

 

이것은 DDD 도메인 주도 설계의 Aggregate Root 개념을 구현할때 유용하다고 한다.