JPA 연관관계 (양방향 연관관계)

smallcherry's techlog·2022년 11월 15일
0
💡 파일서버 구현 시 <파일정보> 엔티티와 <파일URL만료시간> 엔티티 간의 양방향 연관관계를 정의하며 스터디

양방향 연관관계로 설정하게 된 배경

  • 기존엔 ManyToOne 단방향 연관관계였음
  • 파일 정보 삭제 기능을 구현하며 Cascade로 지워져야 하는 부분이 있다는 것을 알게 됨
  • Cascade 설정은 ManyToOne 단방향 관계에서는 설정 하면 안됨! (고아 객체가 생길 위험 때문)
  • 양방향 연관관계 (OneToMany ↔ ManyToOne)를 도입하여, OneToMany 에서 설정하기로 함

연관 관계의 주인

연관 관계의 주인이란?

  • 두 객체가 양방향 관계를 맺을 때, 연관관계의 주인을 정해야 한다.
  • 연관 관계의 주인 지정 == 두 단방향 관계(A→B, B→A) 중 제어의 권한을 갖는 쪽이 어느 것인지 JPA에게 알려 주는 것.
    • 제어의 권한: 외래 키를 비롯한 테이블 레코드를 상대 엔티티를 저장, 수정, 삭제 처리하는 권한
  • 연관 관계의 주인은 조회, 저장, 수정, 삭제 가능, 연관관계의 주인이 아니면 조회만 가능
  • 연관 관계의 주인이 아닌 객체에서 mappedBy 속성을 사용해서 주인을 지정해줘야 한다.
  • 외래 키가 있는 곳을 연관 관계의 주인으로 정하면 된다.
    • FileUrlExpirationTime에서 FileInfo의 Id를 외래 키로 가지고 있으므로 연관관계의 주인은 FileUrlExpirationTime이다.
    • FileInfo에서 mappedBy 속성을 사용해서 FileUrlExpirationTime을 연관 관계의 주인으로 지정

왜 연관 관계의 주인을 지정해야 하는가?

  • 두 객체(FileInfo, FileUrlExpirationTime)가 양방향 연관관계를 가진다.
  • 이 상황에서 FileInfo를 삭제할 때는 FileUrlExpirationTimes도 같이 삭제 되어야 하고, FileUrlExpirationTime이 삭제될 때는 FileInfo의 FileUrlExpirationTimes에서 해당 객체를 삭제해야 함.
  • 애초에 수정할 일이 없다
    • FileInfo에서 FileUrlExpirationTime을 수정할 때 FK를 수정할 지, FileUrlExpirationTime에서 FileInfo를 수정할 때 FK를 수정할 지 혼란이 있을 수 있음.
      • 두 객체 사이의 연관관계 주인을 정해서 명확하게 FileUrlExpirationTime에서 FileInfo를 수정할 때만 FK를 수정하겠다! 라고 정하는 것이다.
  • FileUrlExpirationTime 제어의 권한 가짐 (FileUrlExpirationTime → FileInfo)
    • 조회 시 (FileUrlExpirationTime → FileInfo)
      • FileUrlExpirationTime.getFileInfo()
    • 저장 시 (FileUrlExpirationTime → FileInfo)
      • 굳이 이걸로 할 일 없음
    • 삭제 시 (FileUrlExpirationTime → FileInfo)
      • 굳이 이걸로 할 일 없음
  • FileInfo
    • 조회 시 (FileInfo → FileUrlExpirationTime)
      • 내부적으로.. 비즈니스 로직 상은 x FileInfo.getFileUrlExpirationTimes()
    • 저장 시 (FileInfo → FileUrlExpirationTime)
      • 그럴 일 없어야 함
    • 삭제 시 (FileInfo → FileUrlExpirationTime)
      • 해당 FileInfo 정보를 갖는 FileUrlExpirationTime 객체 모두 삭제되어야 함 → orphanRemoval 옵션을 통해 구현 가능
        • orphanRemoval=true: 부모 엔티티(FileInfo)와 관계가 끊어진 자식 엔티티(FileUrlExpirationTime)를 자동으로 삭제해 줌

orphanRemoval 옵션과 cascade 옵션

💡 관계 설정: 부모 엔티티(FileInfo), 자식 엔티티(FileUrlExpirationTime) 즉, 이 옵션은 부모 엔티티에 있는 자식 엔티티의 @OneToMany 어노테이션의 옵션으로 붙게 됨.

orphanRemoval 옵션

  • orphanRemoval=true
    • 부모 엔티티가 삭제되면 자식 엔티티도 삭제된다.
    • 부모 엔티티가 자식 엔티티의 관계를 제거하면, 자식은 고아로 취급되어 그대로 사라진다.
      • FileInfo.getFileUrlExpirationTimes().remove(0) 했을때, FileUrlExpirationTime 테이블에 해당 인스턴스가 삭제된다.

cascade 옵션

  • cascade=CascadeType.REMOVE
    • 부모 엔티티가 삭제되면 자식 엔티티도 삭제된다.
    • 부모가 자식의 삭제 생명주기를 관리한다.
      • FileInfo가 삭제되면, 해당 FileInfo id를 외래키로 가지는 FileUrlExpirationTime은 삭제된다.
    • 부모 엔티티가 자식 엔티티와의 관계를 제거해도 자식 엔티티는 삭제되지 않고 그대로 남아있다.
      • FileInfo.getFileUrlExpirationTimes().remove(0) 했을때, FileUrlExpirationTime 테이블에 해당 객체는 그대로 남아있다.
  • cascade=CascadeType.PERSISRT
    • 부모가 자식의 전체 생명주기를 관리한다.

Reference

https://jeong-pro.tistory.com/231

JPA CascadeType.REMOVE vs orphanRemoval = true

profile
Java Developer

0개의 댓글