연관관계 주인과 mappedBy
핵심은 객체와 테이블이 연관관계를 맺는 차이를 이해해야한다.
객체 연관관계 = 2개, 즉 객체의 양뱡향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개이다.
- 회원 -> 팀 연관관계 1개 ( 단방향 )
- 팀 -> 회원 연관관계 1개 ( 단방향 )
테이블 연관관계 = 1개, 즉 테이블은 외래키 하나로 두 테이블의 연관관계를 관리한다.
- 회원 <-> 팀의 연관관계 1개 ( 양뱡향 )
그렇다면 객체 Member 의 team 값이 바뀌었을 때 테이블 MEMBER 의 외래키 값으로 업데이트 되야하나? 아니면 객체 Team 의 members 의 값이 바뀌었을 때 업데이트 되야하나?
따라서 둘 중하나로 외래키를 관리해야한다.

- 그래서 나온 개념이
연관관계의 주인 ( Owner )이다.
연관관계의 주인 ( Owner )
양방향 매핑 규칙
- 객체의 두 관계중 하나의 연관관계의 주인으로 지정한다.
연관관계의 주인만이 외래 키를 관리한다. ( 등록, 수정 )주인이 아닌쪽은 읽기만 가능하다.- 주인은 mappedBy 속성을 사용하지 않는다.
- 주인이 아니면 mappedBy 속성으로 주인을 지정한다.
그렇다면 누구를 주인으로 해야하지?
- 외래 키가 있는 곳을 주인으로 정해야한다.
- 아래의 그림에서는 Member.team 이 연관관계의 주인이다.

연관관게의 주인에 따른 자주하는 실수 및 주의점
연관관게의 주인에 따른 자주하는 실수
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가지 문제가 생긴다.
- 위에서 영속성 컨텍스트 내의 SQL 지연 저장소의 쿼리을 DB 로 적용시키는 행위( flush ), 영속성 컨텍스트를 비우는 행위( clear ) 를 하지 않았을 때, Team 객체를 1차 캐시에서 가져오게 된다. 따라서 DB 에 Team 과 Member 의 연관관계가 DB 에 반영되지 않은 상태이기 때문에
List<Member> members = findTeam.getMembers();에서 멤버 리스트를 가져올 수 없다. - 테스트 케이스를 작성할 때 JPA 없이 순수하게 자바 코드상태로 테스트를 하기 때문에 위와 같이 멤버 리스트가 null 값이 나올 수 있다.
- 위에서 영속성 컨텍스트 내의 SQL 지연 저장소의 쿼리을 DB 로 적용시키는 행위( flush ), 영속성 컨텍스트를 비우는 행위( clear ) 를 하지 않았을 때, Team 객체를 1차 캐시에서 가져오게 된다. 따라서 DB 에 Team 과 Member 의 연관관계가 DB 에 반영되지 않은 상태이기 때문에
양방향 연관관계 주의
- 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정해야한다.
- 양방향 매핑시 무한 루프를 조심해야한다. ex ) toString(), lombok, JSON 생성 라이브러리
양방향 매핑 정리
- 단방향 매핑만으로도 이미 연관관계 매핑은 완료된다.
- 양방향 매핑은 반대방향으로 조회( 객체 그래프 탐색 ) 기능이 추가된 것 뿐이다.
- JPQL 에서 역방향으로 탐색할 일이 많기 때문이다.
- 따라서, 초반 설계 할 때에는 단방향 매핑으로 설계를 완료하고 양방향은 필요할 때 추가해도 된다. ( 테이블에 영향을 주지 않기 때문에 )
REFERENCES
'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 |