Spring Data

연관관계 주인과 mappedBy

rohyun 2021. 11. 3. 23:37

연관관계 주인과 mappedBy


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

  • 객체 연관관계 = 2개, 즉 객체의 양뱡향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개이다.

    • 회원 -> 팀 연관관계 1개 ( 단방향 )
    • 팀 -> 회원 연관관계 1개 ( 단방향 )
  • 테이블 연관관계 = 1개, 즉 테이블은 외래키 하나로 두 테이블의 연관관계를 관리한다.

    • 회원 <-> 팀의 연관관계 1개 ( 양뱡향 )
  • 그렇다면 객체 Member 의 team 값이 바뀌었을 때 테이블 MEMBER 의 외래키 값으로 업데이트 되야하나? 아니면 객체 Team 의 members 의 값이 바뀌었을 때 업데이트 되야하나?

  • 따라서 둘 중하나로 외래키를 관리해야한다.

mappedby

  • 그래서 나온 개념이 연관관계의 주인 ( Owner ) 이다.

연관관계의 주인 ( Owner )

  • 양방향 매핑 규칙

    • 객체의 두 관계중 하나의 연관관계의 주인으로 지정한다.
    • 연관관계의 주인만이 외래 키를 관리한다. ( 등록, 수정 )
    • 주인이 아닌쪽은 읽기만 가능하다.
    • 주인은 mappedBy 속성을 사용하지 않는다.
    • 주인이 아니면 mappedBy 속성으로 주인을 지정한다.
  • 그렇다면 누구를 주인으로 해야하지?

    • 외래 키가 있는 곳을 주인으로 정해야한다.
    • 아래의 그림에서는 Member.team 이 연관관계의 주인이다.

mappedbyowner

연관관게의 주인에 따른 자주하는 실수 및 주의점

연관관게의 주인에 따른 자주하는 실수

Team team = new Team();
team.setName("TeamA");
em.persist(team);

Member member = new Member();
member.setName("member1");

// 순방향 ( 주인인 방향 ) 연관관계를 설정한 맞는 케이스
member.setTeam(team)
em.persist(member);

// 역방향( 주인이 아닌 방향 )만 연관관게를 설정한 잘못된 케이스
// JPA 상으로 읽기 전용의 값이기 때문에 테이블에 영향을 미치지않는다.
team.getMembers().add(member);

// em.flush();
// em.clear();

Team findTeam = em.find(Team.class, team.getId()); // 1차캐시에서 가져온다.
List<Member> members = findTeam.getMembers();

for (Member m : members) {
  System.out.println("m = " + m.getUsername());
}
  • team.getMembers().add(member); 의 경우 명시를 해주지 않아도 팀에 속해있는 멤버 리스트를 불러올 수 있다.
  • 하지만 명시를 해주지 않는 것은 객체지향스럽지않고, 2가지 문제가 생긴다.
    1. 위에서 영속성 컨텍스트 내의 SQL 지연 저장소의 쿼리을 DB 로 적용시키는 행위( flush ), 영속성 컨텍스트를 비우는 행위( clear ) 를 하지 않았을 때, Team 객체를 1차 캐시에서 가져오게 된다. 따라서 DB 에 Team 과 Member 의 연관관계가 DB 에 반영되지 않은 상태이기 때문에 List<Member> members = findTeam.getMembers(); 에서 멤버 리스트를 가져올 수 없다.
    2. 테스트 케이스를 작성할 때 JPA 없이 순수하게 자바 코드상태로 테스트를 하기 때문에 위와 같이 멤버 리스트가 null 값이 나올 수 있다.

양방향 연관관계 주의

  • 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정해야한다.
  • 양방향 매핑시 무한 루프를 조심해야한다. ex ) toString(), lombok, JSON 생성 라이브러리

양방향 매핑 정리

  • 단방향 매핑만으로도 이미 연관관계 매핑은 완료된다.
  • 양방향 매핑은 반대방향으로 조회( 객체 그래프 탐색 ) 기능이 추가된 것 뿐이다.
  • JPQL 에서 역방향으로 탐색할 일이 많기 때문이다.
  • 따라서, 초반 설계 할 때에는 단방향 매핑으로 설계를 완료하고 양방향은 필요할 때 추가해도 된다. ( 테이블에 영향을 주지 않기 때문에 )

REFERENCES

김영한님 자바 ORM 표준 JPA 프로그래밍 - 기본편

'Spring Data' 카테고리의 다른 글

JPA Open Session In View  (0) 2021.11.03
JPA 변경감지와 병합  (0) 2021.11.03
JPA Proxy  (0) 2021.11.03
@OneToOne, @ManyToMany  (0) 2021.11.03
JPA 영속성 컨텍스트  (0) 2021.11.03