[TIL] JPA 영속성 전이와 고아 객체: Cascade vs OrphanRemoval 정리

2025. 12. 16. 17:50·Archive/TIL

1. 핵심 주제

JPA에서 부모 엔티티와 자식 엔티티의 생명주기를 관리하는 두 가지 옵션, **CascadeType**과 **orphanRemoval**의 정확한 차이와 사용법을 정리한다.


2. 가장 헷갈리는 차이점: REMOVE vs orphanRemoval

둘 다 "삭제"와 관련되어 있어서 혼동하기 쉽지만, **삭제가 발동되는 조건(Trigger)**이 다르다.

A. 비교 분석

구분 CascadeType.REMOVE orphanRemoval = true
핵심 개념 행동 전파 (Action Propagation) 관계 정리 (Relationship Management)
발동 시점 repo.delete(parent) 호출 시 1. repo.delete(parent) 호출 시 (기본 포함)

2. parent.setChild(null) 로 연결 끊을 시
비유 순장(殉葬)

"내가 죽으면 너도 같이 죽자."
토사구팽(兎死狗烹)

"너랑 연 끊을 거니까 넌 이제 죽어라."
결과 부모가 삭제되면 자식도 삭제됨. 부모가 삭제되거나, 부모에게 버림받으면(참조 해제) 삭제됨.

B. "참조 제거"란 무엇인가?

자바 코드 상에서 부모가 자식을 더 이상 참조하지 않도록 null을 넣거나 리스트에서 remove 하는 행위.

  • CascadeType.ALL만 있을 때:
    • member.setProfile(null); -> DB 삭제 안 됨.
    • 연결 고리(FK)만 끊기고 데이터는 DB에 미아처럼 남음 (쓰레기 데이터).
  • orphanRemoval = true가 있을 때:
    • member.setProfile(null); -> DB 자동 삭제 (DELETE 쿼리 전송).
    • 주인 없는 고아 객체는 가차 없이(칼같이) 삭제해버림.

3. CascadeType의 종류 (영속성 전이)

Cascade는 부모가 겪는 상황을 자식에게 "전파"하는 옵션이다.

  • ALL: 모든 전이 기능 포함 (가장 많이 사용)
  • PERSIST: 저장(save) 전파. (부모 저장하면 자식도 자동 저장)
  • REMOVE: 삭제(delete) 전파.
  • MERGE: 병합(merge) 전파. (수정 사항 반영)
  • REFRESH: 새로고침 전파.
  • DETACH: 비영속 전파. (JPA 관리 대상에서 제외)

4. 누가 부모(Parent)인가? (개념 바로잡기)

흔히 "외래키(FK)를 가진 쪽이 부모 아닌가?"라고 오해하기 쉽지만, JPA 엔티티 관계에서는 반대다.

A. 부모 (LifeCycle Owner)

  • 정의: Cascade나 orphanRemoval 옵션을 설정한 쪽.
  • 특징: 생명주기를 주도한다. "나 죽을 때 따라와"라고 명령하는 쪽.
  • 코드 위치: 보통 mappedBy가 있는 쪽 (외래키 없음).

B. 자식 (Foreign Key Owner / 연관관계의 주인)

  • 정의: @JoinColumn (외래키)을 가지고 있는 쪽.
  • 특징: DB 테이블에 누가 내 주인인지 적어두는 쪽.
  • 코드 위치: @JoinColumn이 있는 쪽.

C. 내 코드 예시

Java
// [부모] Member : 옵션을 설정함 (생명주기 관리자)
@OneToOne(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private Profile profile;

// [자식] Profile : 외래키를 가짐 (연관관계 주인)
@JoinColumn(name = "user_id") 
private Member member;

요약: Member(부모)가 Profile(자식)을 관리한다. Profile은 user_id라는 명찰(FK)을 달고 Member를 따라다닌다.


5. 실무 사용 가이드 (Best Practice)

언제 써야 하는가? (orphanRemoval = true)

자식 엔티티가 "특정 부모에게만 소유되는(Private Owned) 관계" 일 때.

  • 게시글 - 댓글 (게시글 지워지면 댓글 의미 없음)
  • 주문 - 주문상품 (주문 취소되면 상품 내역 의미 없음)
  • 첨부파일 (글 지워지면 파일 의미 없음)

언제 쓰면 안 되는가?

자식 엔티티가 "여러 곳에서 공유되는 관계" 일 때.

  • 회원 - 팀 (회원이 탈퇴한다고 팀을 폭파시키면 안 됨)
  • 상품 - 카테고리 (상품 삭제한다고 카테고리 없애면 안 됨)

6. 결론

코드를 짤 때 CascadeType.ALL과 orphanRemoval = true를 함께 쓰면 부모 엔티티를 통해서 자식의 생명주기(생성, 수정, 삭제)를 완벽하게 관리할 수 있다.

Java
// Member(부모)만 건드려도 Profile(자식)이 알아서 관리됨
memberRepository.save(member);   // Profile도 자동 저장 (Cascade)
memberRepository.delete(member); // Profile도 자동 삭제 (Cascade)
member.setProfile(null);         // Profile 자동 삭제 (orphanRemoval)

이 두 옵션을 적절히 사용하면 자식 Repository를 따로 만들지 않아도 되어 코드가 매우 깔끔해진다. 단, 참조하는 곳이 하나일 때만 사용하자!

'Archive > TIL' 카테고리의 다른 글

[TIL] 지저분한 Service 코드, 정적 팩토리 메서드로 깔끔하게 정리하기  (0) 2025.12.30
[TIL] 웹 데이터의 변신과 여행: 직렬화부터 JWT 저장까지  (0) 2025.12.29
[TIL] REST API 인증과 상태 관리: Session vs Token 정리  (0) 2025.12.09
[TIL] 리액트 핵심 이론 정리: 제이쿼리 차이, 클로저, 비동기  (0) 2025.12.05
[TIL] 리액트 라우팅과 전역 상태 관리: Router & Context API  (1) 2025.12.02
'Archive/TIL' 카테고리의 다른 글
  • [TIL] 지저분한 Service 코드, 정적 팩토리 메서드로 깔끔하게 정리하기
  • [TIL] 웹 데이터의 변신과 여행: 직렬화부터 JWT 저장까지
  • [TIL] REST API 인증과 상태 관리: Session vs Token 정리
  • [TIL] 리액트 핵심 이론 정리: 제이쿼리 차이, 클로저, 비동기
tlsgkstj
tlsgkstj
짱구의 성장 일기
  • tlsgkstj
    코딩하는 짱구
    tlsgkstj
  • 전체
    오늘
    어제
    • 분류 전체보기 (159)
      • About (1)
      • Projects (35)
        • Personal Projects (21)
        • Team Projects (14)
      • Engineering (20)
        • CS & Tools (0)
        • Backend Core (15)
        • Frontend (1)
        • Infra & Cloud (2)
        • AI & Tools (1)
      • Trouble Shooting & Issues (0)
      • Growth & Career (38)
        • Interview Prep (0)
        • Retrospectives (38)
      • Archive (65)
        • TIL (8)
        • Daily Dev Q&A (56)
  • 블로그 메뉴

    • 홈
    • About
    • Projects
    • Tech Stack
    • Dev Log
    • GitHub
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    커리어리셋
    devlog
    경기기후바이브코딩
    spring
    til
    SpringBoot
    데브페스트
    Project_Review
    DevFestIncheon2025
    jpa
    프로덕트개발자
    network
    OrphanRemova
    java
    REACT
    aws_s3
    클로드코드
    backend
    Spring비교
    프로젝트회고
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
tlsgkstj
[TIL] JPA 영속성 전이와 고아 객체: Cascade vs OrphanRemoval 정리
상단으로

티스토리툴바