ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 연관관계 주인 mappedBy 끝내기
    spring/JPA 2021. 5. 5. 12:49

    배경

    cascade 옵션을 공부하면서 양방향 연관관계에서 mappedBy개념을 정리했지만 매번 헷갈린다. 예제를 작성하며 완전히 알고 넘어가보자!

     

     

    개념

    RDB는 양방향 연관관계라는 개념이 없다. 단지 한 테이블이 연관테이블의 FK를 가질 뿐이다. FK는 두 테이블 중 한 테이블만 갖고 있다. 반면 JPA는 양방향 연관관계라는 개념이 있다. 이는 레코드를 객체처럼 관리하기 위함이다. RDB는 조인을 이용해 언제든지 다른 테이블을 참조할 수 있지만 상대 객체의 정보가 없는 객체는 연관 객체를 참조할 수 없다는 점을 보완한 것이다.

     

    엔티티를 설계하면서 연관된 두 엔티티를 단방향으로 설계했다면 딱히 문제될 건 없다. 실제로 양방향보다 단방향으로 관계를 갖는 게 자연스러운 경우가 많다. 그럼에도 양방향으로 관계를 맺어야 하는 경우가 있고 이때 나를 헷갈리게 하는 연관관계 주인이라는 개념이 나온다.

     

    일단 간단하게만 생각하고 예제를 작성해보자. 실제 RDB상에서 FK를 소유하지 않은 테이블과 대응하는 엔티티를 생각해보자. 단방향 설계라면 이 엔티티에 추가적인 작업을 해줄 필요는 없다. 반면 양방향 설계라면 이 엔티티에도 멤버변수에 상대 필드를 추가해줘야 한다. 다만, 결국 RDB 상에서 표현되는 값은 없다. 그저 애플리케이션 레벨에서 사용하는 값일 뿐이다.

     

    명심 : 실제 RDB에서 없는 값이며 애플리케이션에서만 사용한다!

     

     

    Member와 Board

    Member와 Board는 1:1 양방향으로 연관관계를 설정했다. 이때 연관관계의 주인은 Member이며 실제 RDB에서 FK를 갖는 건 Member라는 의미다. 이 의미는 Board는 애플리케이션에서만 member를 사용하며 RDB와는 그값이 전혀 상관없다는 의미다.

     

    의도한 대로 FK가 Member쪽만 있는 걸로 인식해 원하는 대로 쿼리가 생성됐다.

    mappedBy를 제거한 테스트도 진행해보자.

     

    JPA가 FK의 위치를 판단하지 못하고 양쪽에 FK를 넣어버렸다. 객체와 RDB가 올바르게 매핑되지 못한 것이다!

     

     

     

    간단하게 실습해보자.

    분명 board에서 member를 셋하고 저장했는데 멤버를 통한 board조회는 되지 않는다. 쿼리 또한 예측할 수 없는 방향으로 흘러간다. 실제 Board에는 member_id가 없기 때문이다!

    반대로 FK가 있는 member에 board를 set하고 테스트를 진행하면 의도한 대로 쿼리가 정상적으로 수행됐음을 확인할 수 있다.

     

     

    마치며

    mappedBy = "상대 엔티티에서 FK에 해당하는 필드의 변수명" 매번 까먹는다. 여튼 이 옵션을 통해 FK를 정확하게 정할 수 있다. 그리고 생각보다 하이버네이트의 자동화가 너무 뛰어나서 변경감지는 굳이 FK쪽에서 안해도 일어난다. 즉, board.setMember(null)로 해줘도 update member set board_id = null where id = 1과 같이 상대 엔티티를 건드리는 쿼리를 생성해준다. 솔직히 말해서... 놀랍다.

     

     

     

     

     

    댓글

Designed by Tistory.