오봉이와 함께하는 개발 블로그

JPA - 양방향 연관관계와 연관관계의 주인1 - 기본 본문

BE/JPA

JPA - 양방향 연관관계와 연관관계의 주인1 - 기본

오봉봉이 2022. 6. 24. 23:12
728x90

양방향 연관관계와 연관관계의 주인1 - 기본

양방향 매핑


전에 했던 코드는 Member에서는 Team을 얻어올 수 있는 관계 즉, 단방햔 매핑 관계였다.
이제 우리는 Member to Team, Team to Member 모두 얻어올 수 있게 양방향 매핑 관계로 구성을 해야 한다.

테이블에서는 외래키로 조인을 하면 되기 때문에 양방향 참조를 할 때는 테이블에 변화가 생기지 않는다.
즉 테이블에서는 외래키 하나로 양방향을 다 알 수 있기 때문에 사실상 방향이 존재하지 않는다.

하지만, 객체는 아니기 때문에 Team에 Member를 넣어줘야 참조할 수 있다.

코드

멤버는 전과 동일하다.

public class Member {
    @Id
    @GeneratedValue
    private Long id;
    @Column(name = "USERNAME")
    private String name;
//    @Column(name = "TEAM_ID")
//    private Long teamId;
    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}
public class Team {
    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
}

Member에서는 ManyToOne이기 때문에 Team에서는 OneToMany라고 하면 된다.
mappedBy 옵션에 "team"은 Member 클래스의 team이라는 객체 이름으로 매핑이 되어 있다는 뜻이다.

Member findMember = em.find(Member.class, member.getId());

List<Member> members = findMember.getTeam().getMembers();
for (Member m : members) {
    System.out.println("m.getUserName() = " + m.getName());
  }

위 코드를 통해 반대 방향으로 객체 그래프 탐색하여 Member에서 Team으로 다시 Team에서 Member를 찾을 수 있게 됐다.

연관관계의 주인과 mappedBy

객체와 테이블간 연관관계를 맺는 차이를 이해해야 한다.

  • 객체 연관관계는 2개
    • 회원 -> 팀 연관관계 1개(단방향)
    • 팀 -> 회원 연관관계 1개(단방향)
  • 테이블 연관관계는 1개
    • 회원 <-> 팀의 연관관계 1개(양방향)
    • TEAM_ID(FK)를 통해 양쪽 값을 모두 알 수 있다.

객체의 양방향 관계

  • 객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개다.
  • 그래서 객초를 양방향으로 참조하기 위해서는 단방향 연관관계를 2개 만들어야 함.
class A {
  B b;
}
class B {
  A a;
}
  • A -> B (a.getB())
  • B -> A (b.getA())

테이블의 양방향 연관관계

  • 테이블은 외래키 하나로 두 테이블의 연관관계를 관리함.
  • MEMBER.TEAM_ID 외래키 하나로 양방향 연관관계를 가진다
    • 양쪽으로 조인할 수 있다.
SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

SELECT *
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID

객체의 양방향 관계 딜레마


Member to team, Team to members로 가는 참조 값이 있는데, 어떤 걸로 매핑을 해야 할까?

DB에서는 Member 테이블의 TEAM_ID(FK)값만 업데이트 되면 상관없는데
Member의 team 값을 바꿨을 때 외래키가 업데이트 되어야 할까?
Team의 members 값을 바꿨을 때 외래키가 업데이트 되어야 할까?

Member의 team으로 외래키를 관리할지, Team의 members로 외래키를 관리할지 주인을 정해야 한다.

연관관계의 주인(Owner)

  • 양방향 매핑 규칙
    • 객체의 두 관계중 하나를 연관관계의 주인으로 지정
    • 연관관계 주인만이 외래키를 관리(등록, 수정)
    • 주인이 아닌 쪽은 읽기만 가능
    • 주인은 mappedBy 속성 사용하지 않음
    • 주인이 아니면 mappedBy 속성으로 주인 지정

누가 주인이 되어야 할까?

  • 외래키가 있는 곳을 주인으로 정하자
    • 외래키가 있는 곳을 주인으로 정하면 무조건 N 쪽이 연관관계 주인으로 정해진다.
  • 여기서는 Member.team이 연관관계의 주인이 된다.
  • 간단하게 @JoinColumn이 있는 쪽이 주인이다.

Team.members를 주인으로 정해서 값을 바꿨다고 예를 들면 Team.members의 값을 바꿨는데 Member테이블의 값이 변경되는 문제가 생긴다.
이는 연관관계를 이해하기 어려울 뿐더러 매우 햇갈리고 성능 이슈도 발생한다.

출처 : 인프런 김영한 지식공유자님의 스프링 부트와 JPA 실무 완전 정복 로드맵 강의
728x90
Comments