[자바 ORM 표준 JPA 프로그래밍] 6. 다양한 연관관계 매핑

2022. 5. 13. 01:59Web/Spring

반응형

velog에서 옮겨온 글 입니다.

원본 날짜: 2022-03-28T11:57:01.440Z

 

김영한님의 '자바 ORM 표준 JPA 프로그래밍' 서적을 읽고 정리한 글 입니다.

연관 관계 매핑할 때 고려사항 3가지

다중성

다중성을 판단하기 어려울 때는 반대방향을 생각해보면 된다. (일대다의 반대는 항상 다대일이고, 일대일의 반대는 항상 일대일이다)

단방향, 양방향

  • 테이블은 외래키 하나로 양쪽 조인을 할 수 있어서 사실 방향이라는 개념이 없다.
  • 반면에 객체는 참조용 필드를 가지고 있는 객체만 연관된 객체를 조회할 수 있다.
  • 객체 관계에서 한 쪽만 참조하는것을 단방향 관계라 하고, 양쪽이 서로 참조하는 것을 양방향 관계라 한다.

연관관계의 주인

  • JPA는 두 객체 연관관계 중 하나를 정해서 DB 외래 키를 관리하는데 이것을 연관관계의 주인이라 한다.
  • 외래 키를 가진 테이블과 매핑한 엔티티가 외래키를 관리하게 하는 것이 효율적이다.
  • 주인이 아닌 방향은 외래 키를 변경할 수 없고 읽기만 가능하다.
  • 연관관계의 주인은 mappedBy 속성을 사용하지 않는다.

다대일

단방향 [N:1]

  • 회원은 Member.team 으로 팀 엔티티를 참조할 수 있지만, 팀에는 회원을 참조하는 필드가 없다.

양방향 [N:1, 1:N]

  • 외래키가 있는 쪽이 연관 관계의 주인이다.
  • 양방향 연관관계는 항상 서로를 참조해야 한다.

일대다

단방향 [1:N]

  • 1:N에서 1이 연관 관계의 주인이다.
  • 테이블 일대다 관계는 항상 N에 외래 키가 있다.
  • 객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조가 된다.
  • 엔티티가 관리하는 외래 키가 다른 테이블에 있어 update SQL을 추가로 실행해야 하는 단점이 있다.
  • 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자.

양방향 [1:N, N:1]

  • 일대다 양방향 매핑은 존재하지 않는다. 대신 다대일 양방향 매핑을 사용해야 한다.
  • 읽기 전용 필드를 사용해 양방향처럼 사용한다.
  • 일대다 단방향 매핑이 가지는 단점을 그대로 가진다. 따라서, 될 수 있으면 다대일 양방향 매핑을 사용하자.

일대일

  • 일대일 관계는 그 반대도 일대일 관계다.
  • 주 테이블이나 대상 테이블 어느 곳이나 외래 키를 가질 수 있다.

주 테이블에 외래키

  • 주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래키를 두고 대상 테이블을 찾는다.
  • 객체 지향 개발자가 선호한다.
  • JPA 매핑이 편리하다.
  • 주 테이블만 조회하도 대상 테이블에 데이터가 있는지 확인이 가능하다.
  • 값이 없으면 외래 키에 null을 허용하는 단점이 있다.

대상 테이블에 외래키

  • 대상 테이블에 외래키가 존재한다.
  • 전통적인 DB 개발자가 선호한다.
  • 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조를 유지한다.
  • 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩된다.
    • JPA 입장에서는 프록시가 생기기 위해서는 Member의 locker에 값이 있는지 미리 알아야 한다.
    • 근데 이 값을 알려면 멤버만 조회하는 게 아니라 라커 테이블도 어차피 함께 쿼리해야 값이 존재한다는 걸 확인할 수 있는 것이다.
    • 어차피 쿼리가 나갔으니 프록시로 만들 이유가 없어서 즉시 로딩된다.

다대다

  • @ManyToMany 를 사용한다.
  • @JoinTable 로 연결 테이블을 지정한다.
  • 관계형 데이터베이스는 정규화된 테이블 2개라 다대다 관계를 표현할 수 없다.
  • 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 한다.

한계

  • 간편해 보이지만 실무에서 쓰면 안된다.
  • 연결 테이블은 단순히 연결만 하고 끝나지 않는다. 주문 시간, 수량 같은 데이터가 필요해도 위의 그림처럼 데이터를 추가할 수가 없다.
  • 쿼리가 이상하게 나가는 문제도 있다. 중간 테이블이랑 조인해서 나가야 하는데 중간 테이블이 숨겨져 있기 때문에 내가 모르는 쿼리가 나가서 문제가 생길 수 있다.

연결 엔티티 사용

  • 연결용 테이블 엔티티를 추가한다. 즉, 연결 테이블을 엔티티로 승격한다.
  • 다대다를 일대다, 다대일로 풀어낸다.
  • 중간 테이블은 Orders 같은 의미있는 이름으로 변경해도 된다.
반응형