Spring에서 연관관계를 매핑한다고 한다면 대표적으로 단방향 또는 양방향일 텐데
오늘은 둘 중에 양방향에 대해 이야기해보겠습니다.
JPA 프로그래밍 책을 기반으로 작성하였습니다.
양방향이란?
위에 객체 연관관계를 살펴보자면 보다시피 Member와 Team은 다대일 관계이다. 반대로 하면 일대다 관계이다.
일대다는 여러 개와 연관관계를 맺기 때문에 컬렉션을 사용하여 Team.members를 List로 선언한 것을 볼 수 있다.
여기서 List로 컬렉션을 추가하였다고 무조건 List만 쓸 수 있는 것이 아닌 Collection, Set, Map과 같은 다양한 컬렉션을 지원하기 때문에 필요에 따라서 사용하면 된다.
테이블의 관계
데이터베이스에서 테이블은 외래 키 단 하나로도 양방향으로 조회가 가능하다. 그래서 객체와 다르게 데이터베이스는 건드릴 부분이 존재하지 않는다. 테이블에서 TEAM_ID를 사용하여 MEMBER JOIN TEAM이 가능하고 반대로도 가능하다.
연관관계 매핑
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
-----------------------------
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
코드를 보면 팀과 회원은 일대다 관계이고 팀 엔티티에 회원을 매핑하기 위해 `List <Member> members`를 추가하였다.
그리고 mappedBy를 사용한 것을 볼 수 있다. 이 속성은 양방향 매핑을 사용할 때 사용하는 것인데 매핑한 반대쪽의 필드 이름을 값으로 입력하면 된다.
연관관계의 주인
이제 아까 @OneToMany에 속성으로 추가하였던 mappedBy에 대해 이야기해 볼 것이다. @OneToMany만 추가하면 되지 굳이 mappedBy는 왜 필요할까?라는 의문이 들 수밖에 없다.
사실 객체에는 양방향 연관관계라는 것은 존재하지 않는다. 그냥 서로 단방향 연관관계 2개를 로직으로 잘 포장해서 양방향인 듯하지만 전혀 아니다. 하지만 아까 말했듯 데이터베이스는 외래키 하나로도 양방향으로 조인이 가능하다.
현재 연관관계 상태
객체
- 회원 -> 팀(단방향)
- 팀 -> 회원(단방향)
테이블
- 회원 -> 팀(양방향)
이렇게 엔티티를 양방향으로 설정하면 객체가 참조하는 것은 두 개인데 데이터베이스의 외래 키는 하나만 존재한다. 그래서 이 둘 사이에서 차이가 발생할 수밖에 없다. 그러한 점을 고려하여 두 객체 연관관계 중에 하나를 골라서 테이블의 외래 키를 관리하여야 되기 때문에 이것을 연관관계의 주인이라고 한다.
양방향 매핑의 규칙
양방향 매핑을 사용할 시에 지켜야 될 규칙 같은 것이 있다. 그것이 위에서 말한 연관관계의 주인을 정하는 것이다.
연관관계의 주인을 정해야지만 데이터베이스 연관관계에 매핑이 되고 외래 키를 관리를 할 수 있고 반대에서는 읽기만 가능하다.
연관관계의 주인을 정하는 것은 외래키의 관리자를 정하는 것이다. 여기서 회원 테이블에 있는 TEAM_ID 외래 키를 관리하는 관리자를 선택해야 된다. 만약에 회원 엔티티에 있는 Member.team을 주인으로 정하면 자기 테이블에 있는 외래키를 관리하면 된다. 하지만 만약에 Team.members를 주인으로 정하면 전혀 다른 테이블의 외래 키를 관리하여야 한다. 왜냐하면 Team.members가 존재하는 Team 엔티티에는 Team 테이블에 매핑되어 있는데 외래 키를 관리할 테이블은 MEMBER 테이블이기 때문이다.
연관관계의 주인은 외래키가 존재하는 곳
연관관계의 주인은 테이블에 외래 키가 있는 곳에 정해야 맞다. 여기 테이블에서는 회원 테이블이 외래 키를 가지고 있기 때문에 Member.team이 주인이 되는 것이 맞는 주인이다. 그래서 주인이 아닌 Team.members에서는 속성으로 mappedBy로 주인이 아님을 설정하면 된다. 그리고 mappedBy에서 말하는 값은 연관관계의 주인인 Member 엔티티의 team 필드를 말하는 것이다.
정리
연관관계의 주인만 데이터베이스의 연관관계에 매핑되고 외래 키를 관리할 수 있다. 그리고 주인이 아닌 반대쪽은 읽기만 가능하고 외래 키는 변경하지 못한다. 또한 데이터베이스 테이블은 다대일, 일대다 관계에서는 항상 다 쪽에서 연관관계의 주인이 된다. 그래서 다 쪽인 @ManyToOne은 매번 주인이 되기 때문에 mappedBy이 속성에 존재하지 않는다.
'JPA' 카테고리의 다른 글
[JPA] 고아객체? 그게 먼데 (0) | 2024.07.31 |
---|---|
[JPA] 영속성 컨텍스트란? (0) | 2024.03.10 |
[JPA] 1차 캐시란? (1) | 2024.03.05 |