JPA 양방향 관계 (mappedBy)

Panda·2022년 3월 17일
1

Spring

목록 보기
11/42

JPA 에서 모델들을 작성하면서 공부하다가
양방향 관계라는것이 있는데 좋은 내용인거같아서 글을 써봅니다.

데이터베이스를 만들어보자

게임 프로게이머 팀이 있고
그 팀 소속인 선수들이 있다고 가정할 때
데이터베이스를 만들어봅시다!

@Entity
public class Player {

	...
    
    @ManyToOne
    @JoinColumn(name="TEAM_ID")
    private Team team
    
    ...
}
@Entity
public class Team {
	...
    
    @Id @GeneratedValue
    @Column(name ="TEAM_ID")
    private Long no;
    
    ...
}

일반적으로 제가 아는 방법은 이렇게 구성하는 것입니다.

게임프로그래머에서 외래키 설정을 Team의 PK값으로 설정하는 것입니다.
이때 관계는 ManyToOne 입니다.

  • 한명의 선수는 하나의 팀밖에 못가진다.
  • 하나의 팀에는 여러 선수들을 가질 수 있다.

하지만 선수와 팀의 관계는 다대일 단방향 연관관계 이기 때문에 한쪽에서만 참조가 가능합니다.
즉 특정 선수를 조회할때 어떤 팀에 소속되어 있는지 알 수가 있지만
반대로 특정 팀을 조회할때 그 팀에 소속되어 있는 선수들은 알지 못합니다.

이런 상황의 해결방법은 단순합니다.
단방향을 양방향으로 변경해 양쪽에서 서로를 조회 할 수 있게 하면 됩니다.

연관관계 방향에 대해서

여기서 잠깐 방향에 대해서 이해하고 넘어가겠습니다.
실제 DB에서는 방향이란 개념이 존재하지 않습니다.
오직 JPA에서 존재하는 개념입니다.

DB 연관관계

DB와 JPA의 차이점을 명확히 해야 하는데, 먼저 DB에서는 두 테이블의 연관관계를 외래키(FK)를 이용해 JOIN을 하여 찾게 됩니다.
PLAYER 테이블에서 연관관계를 찾으려면 외래키(FK)인 TEAM_ID를 이용해서 JOIN을 하면 되고 TEAM 테이블에서 연관관계를 찾으려면 자신의 PK인 TEAM_ID로 JOIN을 하면 됩니다.

즉, 데이터베이스 세계에서는 연관관계의 방향성이라는 것이 존재하지 않습니다.

JPA 연관관계

객체로 표현되는 JPA에서는 객체를 참조하는 방식으로 두 엔티티의 연관관계를 찾게 됩니다. (중요!)
PLAYER Entity에서 TEAM을 찾거나(PLAYER.team) 혹은 반대로 TEAM엔티티에서 PLAYER를 찾게(TEAM.player) 할 수도 있습니다.
즉, JPA에서 양방향 연관관계란 사실은 단방향 연관관계 두개를 서로 바라보게 해 놓은 형태인 것입니다.

DB에는 없는 구조가 JPA에 존재하기 때문에, JPA에서는 외래키(FK)를 어느 객체에서 관리할지를 명시해 주어야 합니다.
따라서 mappedBy는 두 객체 중 외래키(FK)를 관리할 곳이 어디인지를 알려주는 것이며, FK를 관리하게 되는 객체가 연관관계의 주인이 된다. (만약 mappedBy를 명시하지 않는다면 JPA는 두 엔티티가 양방향 관계임을 모름)

양방향 관계로 바꿔보자

@Entity
public class Player { // DB 테이블로 보았을 때 PLAYER가 외래 키를 가지고 있으므로

	...
    
    @ManyToOne
    @JoinColumn(name="TEAM_ID")
    private Team team // Player에 속한 team이 연관관계의 주인이다.
    
    ...
}
@Entity
public class Team { // TEAM Entity 연관관계의 주인이 아니므로,

	...
    
    @OneToMany(mappedBy = "team")  // TEAM Entity에 속한 players에 mappedBy를 추가해 준다.
    private List<Player> players = new ArrayList<Player>();
    
    ...
}

양방향 관계는 단방향 관계가 2개가 된거이므로
Team Entity에 연관관계를 추가해주면 됩니다.

여기서 mappedBy가 무엇이냐?
mappedBy는 JPA 엔티티의 양방향 연관관계에서 연관관계의 주인을 명시하는 것입니다.

연관관계 주인은 또 어떻게 아냐?
JPA에서는 양방향 연관관계에서 외래 키가 있는 쪽이 연관관계의 주인이라고 합니다.
즉 여기서는 외래키를 가지고 있는 PLAYER Entity가 연관관계 주인이고
더 정확히는 Player Entity 멤버변수이고 외래키인 team 이 연관관계 주인 입니다.

저는 이 개념이 좀 많이 헷갈렸는데 좀더 많이 사용하면 알 것 같긴합니다. ㅋㅋㅋ

가장 중요한 점은, 외래키(FK)는 연관관계의 주인만 관리할 수 있다. "관리" 란, 외래키(FK)를 등록하거나 수정하고 DB에 접속하여 그 값을 바꿀 수 있다는 것을 의미합니다.
즉 Player Entity만이 외래키를 관리 할수 있다는 겁니다.

즉 연관관계의 주인이 아닌 객체에서 아무리 등록 혹은 수정 작업을 해도 DB에는 전혀 반영이 되지 않고, 오직 읽기만 가능합니다.

자 이렇게 양방향 관계를 성공적으로 구성했습니다.
이렇게 되면 JPA에서 Player 조회할 때 해당 Team을 알 수 있고
반대로 Team을 조회할 때 소속되어있는 player를 알 수가 있습니다.

실제 DB 구조는 기존과 동일한데
더 편리하게 JPA를 사용할 수 있어서 좋은것 같습니다.

느낀 점

ORM을 사용할때는 그 특성을 제대로 이해해야 되는 것이 매우 중요한 것 같습니다.

DB의 성질과 ORM의 성질은 다르다! 라는걸 알아갑니다.

JPA도 공부할 내용들이 되게 많기 때문에 계속 공부하겠습니다!

profile
실력있는 개발자가 되보자!

0개의 댓글