프로그래밍/JPA

[ JPA ] 연관관계 매핑 기초

후르트링 2022. 4. 13. 17:55
728x90

엔티티들은 대부분 다른 엔티티와 연관 관계가 있습니다.

객체와 테이블의 연관 관계에서 가장 큰 두가지의 차이는

  • 객체는 참조(레퍼런스)로 연관관계를 맺습니다.
  • 테이블은 외래 키를 사용해서 조인(join)을 통해 연관관계를 맺습니다.

이러한 차이점 안에서 객체의 참조와 테이블의 외래키를 매핑하는 방법을 정리하겠습니다.

 

단방향 연관관계

단방향 연관관계는 회원 -> 팀 또는 팀 -> 회원 과 같이 둘 중 한 쪽만 참조하는 것을 단방향 관계라고 말합니다.

객체 및 테이블 연관관계

member와 team이 다음과 같이 연관 관계를 맺고 있습니다.

@Entity
public class Member {
    @Id @GeneratedValue
    @Column(name= "MEMBER_ID")
    private String id;
    private String username;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

@Entity
public class Team {
    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
}
  • 객체의 연관 관계 설정을 위해 Member 객체의 Member.team 필드를 사용하였습니다.
  • 이것은 테이블에서는 MEMBER 테이블에 TEAM_ID를 외래키로 사용한 것입니다.
  • Team과 Member는 1 대 다 관계이기 때분에 @ManyToOne 애노테이션을 사용해서 표현하였습니다.
  • @JoinColumn을 사용하여 외래 키를 매핑 하였습니다.
    • @JoinColumnname 속성을 이용해서 외래키의 이름을 지정합니다.

 

양방향 연관관계

양방향 연관관계는 단방향 연관관계와 다르게 서로 참조하는 구조를 가지고 있습니다.

양방향 연관관계는 다음과 같은 특징이 있습니다.

  • 테이블의 연관관계외래 키 한개로 양방향 연관관계가 구현이 됩니다.
    • DB에서는 방향이라고 이야기 할 것이 없습니다.
    • 외래키 한 개JOIN을 통해 양방향으로 조회를 할 수 있습니다.
  • 객체의 연관관계에서 양방향 연관관계는 사실 2개의 단방향 연관관계 입니다.
@Entity
public class Team{

    @Id @GeneratedValue
    private Long id;
       private String name;

    @OneToMany(mappedBy = "team")
    List<Member> members = new ArrayList<Member>();
}
  • 객체의 연관관계 : 2개
    • Member -> Team
    • Team -> Member
  • 테이블 연관관계 : 1개
    • Member <-> Team / 외래 키 설정된 양방향

Team 엔티티에서 Member로 매핑을 작성하여 양방향 관계를 완성한 것을 확인 할 수 있습니다.

 

연관 관계의 주인

위의 코드에서 @OneToMany 애노테이션 안에 mappedBy= "team"이라는 속성이 있습니다.

mappedBy 속성은 양방향 연관관계에서 주인을 설정하는 속성입니다.

엔티티의 양방향 연관관계에서 주인을 설정하는 이유는 다음과 같습니다.

  • 양방향 관계에서 객체에서 참조는 두개인데 테이블은 외래키 하나로 관리합니다.
  • 두 객체 연관관계 중에 하나를 연관관계의 주인으로 정해서 외래키를 관리합니다.

위의 코드에서 @OneToMany(mappedBy = "team")의 의미는

Member 엔티티에 있는 private Team team을 연관관계의 주인으로 설정한다는 뜻입니다.

결론은 연관 관계의 주인을 정한다는 것은 외래 키 관리자를 선택하는 것입니다.

 

연관 관계 주인 규칙

연관 관계의 주인으로 정하고 외래키를 관리하기 위해서는 다음과 같은 규칙을 따라야 합니다.

  • 연관 관계의 주인만이 외래키를 관리해야 합니다.
    • 데이터의 등록 및 수정 등은 연관 관계의 주인을 통해서만 이루어져야합니다.
  • 연관 관계의 주인이 아닌 쪽은 읽기만 가능합니다.
  • 연관 관계의 주인은 mappedBy 속성을 사용하지 않습니다.
    • 연관 관계의 주인이 아닌 쪽은 mappedBy 속성을 사용하여 주인을 지정해줍니다.

실전 주인 설정 방법

  • DB 설계시에 외래 키가 있는 곳을 주인으로 설정하는 것이 좋습니다.
  • 1 대 다 관계에서는 "다" 쪽이 연관관계의 주인이 됩니다.

양방향 매핑시 주의점

  • 연관 관계의 주인인 곳에 값을 입력하지 않고, 주인이 아닌 곳에 입력하는 경우
    • 주인이 아닌 곳에는 등록, 수정이 되지 않으므로 주인인 곳에 입력해야 합니다.
  • 그러나 영속성 컨텍스트에 입력한 후에 바로 조회를 하게 된다면 1차 캐시에 데이터가 나오므로 연관 관계가 형성되지 않았을 가능성이 있습니다.
    • 이와 같은 순순 객체 상태를 고려하여 항상 양쪽에 값을 설정해주는 것이 안전합니다.
    • addMember() 와 같은 연관 관계 편의 메서드를 작성하여 양쪽에 값을 설정합니다.
  • 양방향 매핑시에 무한 루프가 생길 수 있습니다.
    • to_string()을 사용시에 서로 계속해서 참조하는 무한루프가 발생할 수 있습니다.

정리

  • 사실 단방향 매핑만으로도 연관관계 매핑은 완료됩니다. 양방향 매핑은 필요할 때만 구현합니다.
    • 양방향 매핑은 반대 방향으로 조회 기능이 추가 된 것일 뿐입니다.
    • 단방향 매핑이 잘 되어 있는 상태에서 양방향을 추가한다고 해도 테이블은 단방향 상태 그대로 유지 됩니다.(테이블에 영향이 가지 않습니다.)
  • 연관 관계의 주인은 비즈니스 로직이 아니라 외래 키의 위치를 기준으로 정해야합니다.

'프로그래밍 > JPA' 카테고리의 다른 글

[ JPA ] 다양한 연관 관계 매핑  (0) 2022.04.14
[ JPA ] 영속성 컨텍스트란?  (0) 2022.03.28
[ JPA ] JPA란?  (0) 2022.03.27