본문 바로가기
spring/jpa

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

by 쭈꾸마뇽 2021. 7. 5.

외래키와 연관관계

  • 외래 키를 관리하는 테이블, 객체(엔티티)가 연관관계의 주인입니다.
  • 주인이 아니면 mappedBy 속성을 사용해 주인 필드 이름을 값으로 입력합니다.

다대일(@ManyToOne)

[Member <-> Team]

  • 연관관계의 주인은 항상 다(N)쪽입니다.
  • ERD에서 화살표 실선은 연관관계 주인이며 점선은 주인이 아니라는 표시입니다.
  • 주인이 아닌 객체는 조회를 위한 JPQL이나 객체 그래프를 탐색할 때 사용합니다.
  • 양방향 연관관계는 항상 서로를 참조해야 합니다.
    • 서로를 참조하기 위해선 편의상 메소드를 작성하는 것이 좋습니다.
    • Member의 setTeam()과 Team의 addMember() 메소드가 그런 메소드들입니다.
    • 메소드는 한쪽에만 작성하는 것이 좋으며 양쪽에 다 작성하면 무한루프에 빠질 수 있습니다.
    • 양쪽에 작성할 경우 하나만 호출하면 됩니다. 또한 무한루프에 빠지지 않도록 검사하는 로직도 있습니다.

일대다 단방향의 단점(@OneToMany)

  • 관리하는 외래 키가 다른 테이블에 있다는 점
    • e.g. team.getMembers().getTeamId로 외래 키를 관리하는 비효율이 발생합니다.
      • 소스코드 : TeamTest 
  • 따라서 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용
  • 다른 테이블의 외래 키를 관리해야하는 점은 성능 문제도 있지만 관리도 부담됩니다.
  • 다대일 양방향은 외래 키가 본인 테이블에 있기 때문에 이런 문제가 발생하지 않습니다.

일대다 양방향

  • 일대다 양방향을 쓰려면 주인 엔티티(Member)에 @Joincolumn(insertable=false, updatable = false) 를 지정해 읽기 전용으로 만들어야 합니다. 하지만 일대다 단방향이 가지는 단점을 그대로 가집니다.
  • 따라서 다대일 양방향을 사용해야합니다. 

일대일 관계(@OneToOne)

[Member <-> Locker]

  • 외래 키를 주 테이블, 대상 테이블 둘 중 어느 곳에서든 관리할 수 있습니다. 외래 키를 객체 참조와 비슷하게 사용할 수 있어서 주로 주 테이블에서 관리합니다.

단방향 매핑

  • 일대일 관계에서 대상 테이블에 외래키가 있는 매핑은 JPA에서 지원하지 않습니다.(일대다의 경우 지원)

다대다 관계(@ManyToOne)

다대다는 실무에서 잘 사용하지 않습니다. - 저자 강의 중

  • 이유 :
    • 매핑의 한계 : 연결 테이블이 단순히 연결만 하지않고 추가 컬럼이나 데이터가 생겨날 수 있음
    • 예상치 못한 쿼리문 : 연결 테이블 때문에 내가 예상못한 쿼리문이 나갈 리스크가 있음
  • 결론 : 일대다, 다대일 양방향으로 풀어야 합니다.
  • 사용자 테이블과 상품 테이블을 관계로 풀어낼 때 중간에 연결 테이블을 추가해야 합니다.
    • Member - Member_Product - Product 
  • 객체는 @ManyToMany를 사용해 다대다 관계를 만들 수 있습니다.ㅇ

양방향

  • (주인이 아닌 엔티티에) mappedBy를 추가하고 편의 메소드를 만들어 관리합니다.
    • e.g. Member <-> Product 상호 mappedBy 추가

다대다 매핑의 한계의 극복

  • 연결관계 테이블에 컬럼이 추가됐을 때 @ManyToMany를 사용할 수 없습니다.
  • 일대다, 다대일 관계로 풀어야 합니다.
    • e.g. OrderAmount(수량)이 추가됐을 경우,
      • 연결 테이블 엔티티 MemberProduct 엔티티를 생성해줘야 합니다.
      • Member - MemberProduct 간 1:N(외래키를 가짐) 관계를 설정해줍니다.

복합 기본 키

  • MemberProduct처럼 기본 키가 둘인 경우 별도의 식별자 클래스를 만들어야 합니다.
  • 엔티티에는 @IdClass를 지정해줍니다.

복합키 식별자 클래스(MemberProductId)의 특징에는

  • 별도의 식별자 클래스로 만들어야 합니다.
  • Serializable을 구현해야 합니다.
  • equals와 hashCode 메소드를 구현해야 합니다.
  • 기본 생성자가 있어야 합니다.
  • 식별자 클래스는 public이어야 합니다.
  • @IdClass 외에 @EmbeddedId를 사용하는 방법도 있습니다.

하지만 복합키를 사용할 땐 복잡하다는 단점이 있습니다. 대안으로 대리 키를 사용하는 것입니다.

다대다 연관관계 정리

  • 다대다 관계를 일대다 다대일 관계로 풀어내기 위해 연결 테이블을 만들 때 식별자를 어떻게 구성할지 선택해야 합니다.
    • 식별 관계 : 받아온 식별자를 기본 키 + 외래 키로 사용
    • 비식별 관계(Order.class) : 받아온 식별자는 외래 키로만 사용하고 새로운 식별자를 추가

2번 방법이 복합키를 위한 식별자를 만들지 않아도 되므로 편리하게 ORM 매핑을 할 수 있습니다.

  • 소스코드 : ProductTest

출처 : 자바 ORM 표준 JPA 프로그래밍 스터디

 

klyhyeon/JPAStudy

Contribute to klyhyeon/JPAStudy development by creating an account on GitHub.

github.com

 

댓글