[JPA] 양방향 연관관계 (1)
23 Jun 2022해당 포스트는 인프런 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 듣고 정리한 글입니다.
양방향 연관관계와 연관관계의 주인1 - 기본
양방향 매핑
저번시간에 한 Member와 Team을 양방향으로 매핑하면 아래의 그림처럼 된다. 저번시간엔 Member Entity에 Team의 매핑정보에 대한 객체를 가지고 있으니, 이번엔 Team에 Member의 객체를 추가하고자 한다.
양방향 매핑을 위해 Team 에 Member 의 목록을 받아온다.
@Entity
@Getter @Setter
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
/* Collection 객체는 초기화해주는 관례 */
/* OneToMany를 선언하고 team 과 매핑해줌 */
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
Team team = new Team();
team.setName("TeamA");
entityManager.persist(team);
Member member = new Member();
member.setUsername("member1");
member.setTeam(team);
entityManager.persist(member);
entityManager.flush();
entityManager.clear();
Member findMember = entityManager.find(Member.class, member.getId());
Team findTeam = findMember.getTeam();
List<Member> members = findTeam.getMembers();
System.out.println("findTeam = " + findTeam.getName());
for (Member m : members) {
System.out.println("findMembers = " + m.getId());
}
select
member0_.id as id1_0_0_,
member0_.TEAM_ID as team_id3_0_0_,
member0_.USERNAME as username2_0_0_,
team1_.id as id1_1_1_,
team1_.name as name2_1_1_
from
Member member0_
left outer join
Team team1_
on member0_.TEAM_ID=team1_.id
where
member0_.id=?
findTeam = TeamA
select
members0_.TEAM_ID as team_id3_0_0_,
members0_.id as id1_0_0_,
members0_.id as id1_0_1_,
members0_.TEAM_ID as team_id3_0_1_,
members0_.USERNAME as username2_0_1_
from
Member members0_
where
members0_.TEAM_ID=?
findMembers = 2
Member를 조회할때 따시 SQL 조인 쿼리를 날려 Member의 목록을 조회해오는것을 볼 수 있다.
연관관계의 주인과 mappedBy
- mappedBy = JPA의 어려운 난이도.
- 객체와 테이블간에 연관관계를 맺는 차이를 이해해야 한다.
객체와 테이블이 관계를 맺는 차이
객체와 테이블은 각각 연관관계를 맺는 방식이 다르다.
객체는 단방향이 두개로 이어져있는것, DB의 경우 FK를 통해서 서로 양방향으로 연관관계를 맺고 있는 것이다.
- 객체 연관관계 = 2개
- 회원 -> 팀 연관관계 1개 (단방향)
- 팀 -> 회원 연관관계 1개 (단방향)
- 테이블 연관관계 = 1개
- 회원 <-> 팀의 연관관계 1개 (양방향)
객체의 양방향 관계
- 객체의 양방향 관계는 양방향 관계가 아닌 서로 다른 단방향 관계 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 T.TEAM_ID = M.TEAM_ID
SELECT *
FROM TEAM T
JOIN MEMBER M ON M.TEAM_ID = T.TEAM_ID
연관관계의 주인 (Owner)
- 양방향 매핑 규칙
- 객체의 두 관계중 하나를 연관관계의 주인으로 지정
- 연관관계의 주인만이 외래 키를 관리 (등록, 수정)
- 주인이 아닌쪽은 읽기만 가능
- 주인은 mappedBy 속성 사용 X
- 주인이 아니면 mappedBy 속성으로 주인 지정
해당 주인을 잘못 지정할 경우, 성능 이슈가 생길 수 있다.
누구를 주인으로?
- 외래 키가 있는 곳을 주인으로 정해라
- 여기서는 Member.team 이 연관관계의 주인이다. (간단하게 말하자면 N 쪽이 되는곳이 주인이 된다고 보면 된다.)