[JPA] 연관관계에서 cascade속성, orphanRemoval 속성 <주의>

조시현·2023년 7월 18일
0

JPA

목록 보기
1/2

잡담

도메인에서 연관관계에서 fetch = FetchType.LAZY를 사용시, 객체를 삭제할 때, 데이터베이스에서 자식관계의 엔티티들과 자식의 자식관계의 엔티티들이 지연로딩으로 인해서 에러가 발생하였다.
그러하여 다양한 방법을 찾는 도중 Cascade와 orphanRemoval 속성을 통한 해결 방법을 찾아서 기쁜 마음으로 지식을 습득하려한다.


영속성 전이 : CASCADE

import javax.persistence.*;

상위 엔터티에서 하위 엔터티로 모든 작업을 전파하고 싶을때 사용하는 옵션이다.
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 같은 영속 상태로 전이되는 것을 의미합니다.

속성들

  • CascadeType.ALL: 모든 Cascade를 적용

  • CascadeType.PERSIST: 엔티티를 영속화할 때, 연관된 엔티티도 함께 유지
    EntityManager를 통해 영속성 객체에 수행하는 행동이 자식까지 전파되는 것이다.

  • CascadeType.MERGE: 엔티티 상태를 병합(Merge)할 때, 연관된 엔티티도 모두 병합

  • CascadeType.REMOVE: 엔티티를 제거할 때, 연관된 엔티티도 모두 제거
    부모 엔티티가 삭제되면 자식 엔티티도 삭제된다.

  • CascadeType.DETACH: 부모 엔티티를 detach() 수행하면, 연관 엔티티도 detach()상태가 되어 변경 사항 반영 X

  • CascadeType.REFRESH: 상위 엔티티를 새로고침(Refresh)할 때, 연관된 엔티티도 모두 새로고침

cascade를 어디에 써야할까??

일대다 연관관계 기준으로 설명드리겠습니다.연관관계의 주인이 항상 多에 존재한다고 알고 계실것입니다.이의 반대쪽 엔티티에 사용하면 된다.
즉, 多가 아닌 一로 시작하는 곳이라고 생각하면 된다.
일대일 연관관계 기준으로는 연관관계의 주인 반대의 쪽에 사용하면 된다.

cascade를 언제 써야할까??

편안한게 그냥 OneToMany에 전부 다 넣으면 되냐라고 생각하실 수도 있습니다.
하지만 그럼 큰일이 발생한다.(의도하지 않은 것들이 사라지거나 오류를 발생시킴)
반드시 의도를 한 곳에만 사용되어야한다.

  1. Cascade되는 하위 엔티티와 Cascade를 설정하는 상위 엔티티의 라이프사이클이 동일하거나 비슷해야한다.

CascadeType.REMOVE는 항상 조심해서 사용하자

경험담: 무분별하게 사용하다가 댓글을 하나 삭제했다가 잘못 쓰여진 한 코드로 인해서, 삭제되면 안되는 데이터가 날아갓다...

고아객체

부모 엔티티와 연관관계가 끊어진 자식 엔티티
cf) 만약 하나의 객체가 2개의 관계가 있다면, 하나만 끊어져도 고아객체의 조건에 부합한다.

orphanRemoval

orphanRemoval = true

고아 객체 제거 : 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제

Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0);

실행 과정 자식 엔티티를 컬렉션에서 제거함 -> 부모객체와의 연관관계 끊어짐 -> DELETE 쿼리 발생(DELETE FROM CHILD WHERE ID = ?)

주의

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

궁금증 정리

CascadeType.REMOVE

이 옵션의 경우에는 엔티티를 em.remove를 통해 직접 삭제할 때,그 아래에 있는 多에 해당하는 엔티티들이 삭제되는 것입니다.
영속성 전이 삭제 옵션은 부모가가 삭제될 때 자식도 영속성 전이 옵션으로 인해 함께 삭제되는 것이지, 부모와 자식의 관계가 끊어졌다 해서 자식을 삭제하지 않기 때문이다.
즉, 부모 엔티티가 자식 엔티티와의 관계를 제거해도 자식 엔티티는 삭제되지 않고 그대로 남아있다.

orphanRemoval = true

이 옵션의 경우에는 부모 엔티티가 자식 엔티티와의 관계를 제거해도 자식 엔티티는 삭제 해주는 옵션이다.
즉, 엔티티의 리스트에서 요소를 삭제하기만 해도 해당 엔티티가 delete되는 기능까지 포함하고 있다고 이해하면 된다.

결론

연관관계에서 cascade속성과 orphanRemoval 속성을 통해서
영속성 전이와 고아 객체를 관리 할 수 있다.

부모가 자식의 전체 생명 주기를 관리하게 된다.
도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용하다.


참고
https://zzang9ha.tistory.com/350
https://velog.io/@syleemk/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%A0%84%EC%9D%B4%EC%99%80-%EA%B3%A0%EC%95%84-%EA%B0%9D%EC%B2%B4
https://hongchangsub.com/jpa-cascade-2/

profile
소프트웨어 관련 고민을 좋아하고 상황에 맞는 답을 함께 찾아가는 과정을 좋아합니다. 😀

1개의 댓글

comment-user-thumbnail
2023년 7월 18일

정말 잘 읽었습니다, 고맙습니다!

답글 달기