언어, 프레임워크/Spring

cascade와 orphanRemoval 비교하기

go_getter 2025. 4. 17. 23:31

cascade = CascadeType.REMOVE을 설정하는 것과 orphanRemoval = true을 설정하는 건 어떤 차이가 있을까

cascade와 orphanRemoval 둘 다 영속성 관리를 위해 사용하는 옵션이다.

 

Cascade

- 부모가 하는 걸 자식이 따라가는 설정

- ex. 부모가 삭제되면 자식도 삭제, 부모가 persist되면 자식도 persist

- 즉, 부모와 자식의 생명주기를 함께 관리하는 개념이다.

 

orphanRemoval

- cascade + 고아객체 삭제 설정 추가

- 즉, 영속성에서 삭제에 대해서만 관리하는 개념이다.

 

고아객체란

부모의 리스트에서 자식을 지우면, 지워진 자식 데이터는 부모의 컬렉션(자식 리스트)에서 떨어져 나오게 된다.

떨어져 나온 자식은 부모가 사라지게 되는데, 이를 고아객체라고 지칭한다.

이때 orphanRemoval=true로 설정해주면 고아객체를 자동으로 삭제해준다.


cascade = CascadeType.REMOVE로 설정하면 부모가 삭제됐을 때 자식도 삭제된다.

  • 부모를 삭제하는 행위(em.remove(parent))가 일어날 때
  • 자식도 같이 삭제 요청이 들어간다.

 

부모를 삭제한 게 아니라 부모가 가진 자식 필드에서 해당 자식을 지우는 경우(관계만 끊는 경우)에는 부모가 가진 자식 리스트에서만 지우고 DB에 있는 자식 테이블에는 그대로 남는다.

  • 메모리 상에서는 자식 리스트에서 빠지지만
  • DB에서는 삭제되지 않고 가비지 데이터로 남는다.

 

DB에서도 깔끔하게 지우기 위해서는 부모 자체를 삭제해 버리거나, 직접 자식 데이터를 remove() 함수로 지워줘야 한다.

  • 부모를 삭제해서 cascade로 자식까지 지우거나
  • em.remove(child) 직접 호출해서 자식만 지워야 한다.

 

orphanRemoval = true로 설정하면 부모가 가진 자식 리스트에서 해당 데이터를 지우기만 해도 JPA가 고아 객체가 된 걸 인지하고 자식 테이블에서도 지워준다.

  • 리스트에서 지우고
  • flush()가 실행되는 시점에 JPA가 자동으로 DB에서 delete 한다.

 

cascade = REMOVE는 부모 삭제할 때만 동작하고, orphanRemoval = true는 연관 끊겼을 때도 자식 삭제까지 해준다.

cascade = REMOVE는 부모가 죽을 때만 따라간다.

orphanRemoval = true는 부모가 버렸을 때도 자식이 죽는다.

 


단방향과 양방향에서의 고아객체 관리 방법

단방향에서는

부모 컬렉션에서 자식을 지우면 해당 자식은 바로 고아객체가 되어, orphanRemoval을 true로 설정하면 바로 삭제된다.

 

양방향에서는

부모의 컬렉션에서 자식을 삭제할 때, 자식.setParent(null)을 해줘야 한다.

부모 측에서는 자식을 지웠지만 자식 측에서는 아직 부모를 참조하고 있기 때문에, JPA가 해당 자식 데이터를 고아객체로 인식하지 못할 수도 있다.