[JPA] 연관관계 매핑 기초 (2) 양방향 연관관계
1. 양방향 연관관계
양방향 연관관계란 다음과 같다
- 회원 -> 팀
- 팀 -> 회원
2. 양방향 연관관계의 매핑
@Entity
public class Member {
@Id
@Column(name = "MEMBER_ID")
private Long id;
private String username;
// 연관관계 매핑
@ManyToOne // 다(Member)대일(Team)
@JoinColumn(name = "TEAM_ID") // 외래키를 매핑할 때 쓰는 annotation. 매핑할 외래키 이름을 씀
private Team team;
// 연관관계 설정
public void setTeam(Team team) {
this.team = team;
}
// Getter, Setter...
}
@Entity
public class Team {
@Id
@Column(name = "TEAM_ID")
private Long id;
private String name;
// 연관관계 매핑
@OneToMany(mappedBy = "team") // 일(Team)대다(Member)
private List<Member> members = new ArrayList<>();
// Getter, Setter...
}
mappedBy 속성은 양방향 매핑을 때 사용하는데 반대쪽 매핑의 필드명을 값으로 주면 된다.
사실 객체에는 양방향이라는 것이 없음. 테이블의 경우에는 FK 하나로 두 테이블이 서로 조인해서 사용 가능하니 양방향이지만, 객체의 경우에는 단방향 2개로 양방향인것 처럼 구현하는 것임.
근데 이렇게 단방향 2개를 사용(즉 양방향)하면, 회원 -> 팀, 팀-> 회원으로 두 곳에서 서로를 참조하므로 관리 포인트가 2개로 늘어나버림.
테이블의 경우에는 FK 하나만 관리하면 되는데..
이런 차이로 인해 JPA 에서는 두 객체 연관관계 중 하나를 정해 테이블의 FK 를 관리하게 하는데 이것을 연관관계의 주인(Owner)라고 함.
3. 양방향 매핑의 규칙: 연관관계의 주인
양방향 연관관계 매핑 시 두 연관관계 중 하나를 주인으로 정해야만 함.
이 주인만이 외래키를 관리(등록, 수정, 삭제)할 수 있고 주인이 아닌 쪽은 읽기만 가능.
누가 주인인지 아닌지를 mappedBy 속성으로 나타내는 것.
- 주인은 mappedBy 속성을 사용하지 않는다.
- 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해야한다.
주인을 정한다는 것은 사실 FK 관리자를 선택하는 것이다.
4. 양방향 연관관계의 주의점
연관관계의 주인만이 외래키의 값을 변경할 수 있다.
즉, Member 객체를 통해서만 필드의 값을 변경할 수 있고, Team 객체를 통해 member 의 값을 변경할 수는 없다.
-> 양방향이라면서..?
-> 고로, 양방향 연관관계는 양쪽 다 신경 써야한다. 양방향이 깨지지 않도록!
아래와 같이 양방향이 깨지지 않도록 구현을 해줘야함.
관계형 DB 에서는 FK 하나로 해결하지만, 객체에서 양방향 연관관계를 사용하려면 로직을 견고히 작성해야함.
public void setTeam(Team team) {
// 기존 팀과의 관계 제거
if (this.team != null) {
this.team.getmembers().remove(this);
}
this.team = team;
team.getMembers().add(this();
}
5. 정리
- 단방향 매핑 만으로 테이블과 객체의 연관관계 매핑을 이미 완료됨.
- 단방향을 양방향으로 만들면 반대방향으로 객체 그래프 탐색 기능이 추가됨.
- 양방향 연관관계를 매핑하려면 객체에서 양쪽 방향을 모두 관리해야함.
연관관계 주인을 정하는 기준은 비즈니스 중요도를 배제하고 단순히 FK 관리자 정도의 의미만 부여해야함.
Reference : 자바 ORM 표준 JPA 프로그래밍 (김영한 저)