본문 바로가기
  • Let's study
BackEnd/Spring

[Spring] orphanRemoval

by 코딩고수이고파 2026. 8. 11.

JPA에서 @OneToMany 관계를 사용하다 보면 부모 엔티티에서 자식 엔티티를 제거했을 때 자식 데이터까지 함께 삭제하고 싶은 경우가 있다.

이때 사용할 수 있는 옵션이 orphanRemoval이다.

1. orphanRemoval이란?

orphanRemoval = true를 설정하면 부모 엔티티와의 연관관계가 끊어진 자식 엔티티를 DB에서도 삭제할 수 있다.

예를 들어 하나의 게시글(Post)에 여러 개의 댓글(PostComment)이 있다고 가정한다.

@Entity
public class Post extends BaseEntity {

    @OneToMany(
        mappedBy = "post",
        cascade = {CascadeType.PERSIST, CascadeType.REMOVE},
        orphanRemoval = true
    )
    private List<PostComment> comments = new ArrayList<>();
}

게시글에서 특정 댓글을 제거한다.

public void removeComment(int commentId) {
    comments.removeIf(comment -> comment.getId() == commentId);
}

이때 orphanRemoval = true가 설정되어 있다면 컬렉션에서 제거된 댓글은 고아 객체로 판단되어 DB에서도 삭제된다.

2. 왜 필요한가?

게시글과 댓글처럼 부모가 자식의 생명주기를 관리하는 관계에서 유용하다.

게시글에 속한 댓글을 단순히 List에서 제거하는 것만으로 끝내는 것이 아니라, 실제 데이터베이스에서도 해당 댓글을 삭제할 수 있기 때문이다.

public void removeComment(int commentId) {
    comments.removeIf(comment -> comment.getId() == commentId);
}

따라서 서비스에서는 다음처럼 객체의 상태만 변경할 수 있다.

@Transactional
public void deleteComment(Post post, int commentId) {
    post.removeComment(commentId);
}

트랜잭션이 종료될 때 JPA가 변경된 상태를 확인하고 필요한 DELETE SQL을 실행한다.

3. CascadeType.REMOVE와는 다르다

CascadeType.REMOVE와 orphanRemoval은 비슷해 보이지만 동작하는 상황이 다르다.

구분 CascadeType.REMOVE orphanRemoval
기준 부모 엔티티 삭제 부모와 자식의 연관관계 제거
예시 Post 삭제 → Comment 삭제 Post에서 Comment 제거 → Comment 삭제
목적 삭제 작업 전파 고아 객체 삭제
questionRepository.delete(question);

처럼 부모 자체를 삭제할 때 자식도 삭제하도록 하는 것이 CascadeType.REMOVE이다.

post.getComments().remove(comment);

처럼 부모는 그대로 두고 자식과의 관계만 끊었을 때 자식까지 삭제하는 것이 orphanRemoval이다.

댓글