일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 연결리스트
- 백트래킹
- JPQL
- 스토어드 프로시저
- 데코레이터
- 즉시로딩
- dfs
- 동적sql
- shared lock
- 다대일
- 비관적락
- PS
- fetch
- 일대다
- 스프링 폼
- 이진탐색
- 힙
- 다대다
- exclusive lock
- execute
- 연관관계
- querydsl
- SQL프로그래밍
- eager
- CHECK OPTION
- BOJ
- 유니크제약조건
- FetchType
- 지연로딩
- 낙관적락
- Today
- Total
흰 스타렉스에서 내가 내리지
[JPA] 연관관계의 주인 , mappedBy, 연관관계 본문
객체에는 양방향 연관관계라는 것이 없다. 서로 다른 단방향 연관관계 2개를 애플리케이션 로직으로 잘 묶어서 양방향인 것처럼 보이게 할 뿐이다.
JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래 키를 관리해야 하는데 이것을 연관관계의 주인 이라 한다.
연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리 (등록, 수정, 삭제) 할 수 있다.
반면에 주인이 아닌 쪽은 읽기만 할 수 있다.
- 주인은 mappedBy 속성을 사용하지 않는다.
- 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해야 한다.
mappedBy 속성은 양방향 매핑일 때 사용하는 데 반대쪽 매핑의 필드 이름을 값으로 주면 된다.
연관관계의 주인을 정한다는 것은 사실 외래 키 관리자를 선택하는 것이다.
연관관계의 주인은 테이블에 외래 키가 있는 곳으로 정해야 한다.
주인이 아닌 곳에는 mappedBy="~~" 속성을 사용해서 주인이 아님을 설정한다.
데이터베이스 테이블의 다대일, 일대다 관계에서는 항상 다 쪽이 외래 키를 가진다.
다 쪽인 @ManyToOne은 항상 연관관계의 주인이 되므로 mappedBy를 설정할 수 없다.
따라서 @ManyToOne에는 mappedBy 속성이 없다.
결론 : @OneToMany(mappedBy = "상대쪽 필드 명") 이 국룰이다.
mappedBy = "주인님은 날 무어라고 일컫는가!!!"
양방향 연관관계 저장
class Member{
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
class Team{
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
}
양방향 연관관계는 연관관계의 주인이 외래 키를 관리한다.
따라서 주인이 아닌 방향은 값을 설정하지 않아도 데이터베이스에 외래 키 값이 정상 입력된다.
양방향 연관관계를 설정하고 가장 흔히 하는 실수는 연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하는 것이다.
team1.getMembers().add(member1); // 무시(연관관계의 주인이 아님)
team1.getMembers().add(member2); // 무시(연관관계의 주인이 아님)
member1.setTeam(team1); // 연관관계 설정(연관관계의 주인)
member2.setTeam(team2); // 연관관계 설정(연관관계의 주인)
Team.members는 연관관계의 주인이 아니다.
주인이 아닌 곳에 입력된 값은 외래 키에 영향을 주지 않는다.
따라서 위 코드는 데이터베이스에 저장될때 무시된다.
그럼 정말 연관관계의 주인에만 값을 저장하고 주인이 아닌 곳에는 값을 저장하지 않아도 될까?
사실 객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다.
양쪽 방향 모두 값을 입력하지 않으면 JPA를 사용하지 않는 순수한 객체 상태에서 심각한 문제가 발생할 수 있다.
연관관계 편의 메소드
두 코드를 각각 호출하면 실수로 둘 중 하나만 호출해서 양방향이 깨질 수 있다.
양방향 관계에서 두 코드는 하나인 것처럼 사용하는 것이 안전하다.
public class Member{
private Team team;
public void setTeam(Team team){
// 연관관계를 변경할 때 기존 팀이 있으면 기존 연관관계 삭제
if(this.team != null){
this.team.getMembers().remove(this);
}
this.team = team;
team.getMembers().add(this);
}
}
아니 어차피 주인이 아니라 db에는 반영 안 돼서 상관 없지 않느냐? 라고 하면,
문제는 관계를 변경하고 영속성 컨텍스트가 아직 살아있는 상태에서 teamA의 getMembers()를 호출하면 member1이 반환된다는 점이다. 따라서 변경된 연관관계는 관계를 직접 제거해주는 것이 안전하다.
'Spring' 카테고리의 다른 글
[JPA] 연관관계 - 다대다 @ManyToMany, 복합 키, 식별자 클래스, @IdClass (0) | 2023.02.10 |
---|---|
[JPA] 연관관계 - 다대일,일대다,일대일,@ManyToOne,@OneToMany,@OneToOne (0) | 2023.02.10 |
[JPA]@Access(AccessType.PROPERTY) (0) | 2023.02.10 |
[JPA] @Transient (0) | 2023.02.10 |
[JPA] @Temporal - 날짜시간타입 매핑 (0) | 2023.02.10 |