JPA

[JPA] 양방향 연관관계와 연관관계의 주인

수수한개발자 2022. 6. 15.
728x90

인프런 강의 참고

JPA는 영속성컨텍스트의 매커니즘 이해와 양방향연관관계와 연관관계의 주인을 정해주는 이부분이 가장 헷갈리고 어렵다고 합니다.

왜 어렵냐하면 객체랑 테이블이 두개가 패러다임차이 때문입니다..

객체는 연관되어있는것들을 '참조'라는것을 사용하고 

데이터베이스는 테이블은 '외래키'를 가지고 조인을 활용한다.

두개의 차이와 차이에서오는것을 이해를 해야 연관관계의 주인이라는 개념이라는게 있다는걸 알게되고 이해 할 수 있습니다.

 

양방향 매핑

 

[JPA] 양방향 연관관계와 연관관계의 주인 - 양방향 매핑

테이블 연관관계를 보면 단방향 연관관계에서의 연관관계와 차이가 하나도 없는것을 알 수 있습니다.

멤버에서 팀을알고싶으면  멤버의 TEAM_ID와 팀의 TEAM_ID를 조인하면 되고 팀 테이블에서 우리팀의 멤버가 누가있는지 알고 싶으면 팀의 TEAM_ID와 멤버의 TEAM_ID를 조인하면됩니다. 

여기서 중요한것을 테이블의 연관관계는 외래키 하나로 양방향이 다 있는것입니다.

사실상 테이블에서는 양방향이라는 개념이 없습니다. 포링키하나넣으면 양쪽(연관관계)으로 다 알 수있습니다.

문제는 객체입니다.

멤버 객체에 팀객체를 가지고 있으면 멤버에서 팀은 갈 수있지만 팀에서는 멤버를 갈 수  있는 방법이 없었습니다.

그래서 팀객체에 members라는 List를 넣어주어야 갈 수 있습니다. 이렇게 객체의 참조와 테이블의 외래키의 가장 큰 차이입니다.

 

양방향 매핑 (Member 엔티티는 단방향과 동일)

 

@Entity
 public class Member { 
     @Id @GeneratedValue
     private Long id;
     @Column(name = "USERNAME")
     private String name;
     private int age;
     @ManyToOne
     @JoinColumn(name = "TEAM_ID")
     private Team team;
 … 
}

양방향 매핑 (Team 엔티티는 컬렉션 추가)

 

@Entity
 public class Team {
     @Id @GeneratedValue
     private Long id;
     private String name;
     @OneToMany(mappedBy = "team")
     List<Member> members = new ArrayList<Member>();
     … 
 }

양방향 매핑 (반대 방향으로 객체 그래프 탐색)

 

//조회
 Team findTeam = em.find(Team.class, team.getId()); 
 int memberSize = findTeam.getMembers().size(); //역방향 조회

이러면 양쪽에서 다 참조 할 수 있는 엔티티가 되었습니다.

여기서 팀객체의 @OneToMany(mappedBy ="team") 에서 mappedBy는 

mappedBy = "team"

나의 반대편사이드에는 team(변수) 가 걸려있어~(매핑이 되어 있다.) 라고 적어 주어야합니다.

 

연관관계의 주인과 mappedBy

객체는 가급적이면 단방향이 좋다.

mappedBy 정체

mappedBy = JPA의 멘탈붕괴 난이도 입니다.

이론적인이유, 왜 이런식으로 jpa가 설계했는지 모르고 쓰면 이걸 어느타이밍에써야할지 감이 안온다.

그러므로 현업에서 알 수 없는, 값이 안들어가는 오류가나면 대처 할 수 없겠죠?

처음에는 이해하기 어렵습니다. 이해하려면 객체와 테이블간에 연관관계를 맺는 차이를 이해해야합니다. .

 

객체와 테이블이 관계를 맺는 차이

[JPA] 양방향 연관관계와 연관관계의 주인 - 객체와 테이블이 관계를 맺는 차이

 

객체는 연관관계가되는 포인트가 2가지가있습니다.

• 회원 -> 팀 연관관계 1개(단방향)

• 팀 -> 회원 연관관계 1개(단방향) 

 

위의 그림을 잘보면 단방향 연관관계가 두개가 있습니다.

- 멤버에서 팀으로가는 연관관계 1개

- 팀에서 멤버로가는 연관관계 1개 

그래서 객체에서의 양방향연관관계는 단방향 연관관계가 2개가 있고 이를 억지로 양방향연관관계라고 하는 것이다.

 

테이블 연관관계는 키포인트가 하나입니다.

[JPA] 양방향 연관관계와 연관관계의 주인 - 객체와 테이블이 관계를 맺는 차이

MEMBER테이블의 TEAM_ID를 TEAM테이블의 PK와 join하면 이 멤버가 어느팀소속인지 알수가있습니다.

TEAM입장에서도 TEAM_ID(PK)의 외래키를 조인하면 우리팀에 누가 있는지 알 수있습니다.

테이블의 연관관계는 FK (포링키)하나로 끝이 납니다.

사실 테이블끼리는 방향이 없습니다.하나만 있으면 양쪽으로 왔다갔다 할 수 있기 때문에입니다,

여기에서 테이블과 객체의 차이를 이해하시면 여기가 출발점입니다!

 

객체의 양방향 관계

[JPA] 양방향 연관관계와 연관관계의 주인 - 객체의 양방향 관계

위에서말한 객체의 양방향관계 예제 입니다.

양방향관계가아니라 서로다른 단방향 관계 2개입니다.

객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 합니다.

 

이렇게 객체와 테이블의 차이가 있으니 객체에서는 둘중에  하나로 외래키를 관리해야 됩니다.

[JPA] 양방향 연관관계와 연관관계의 주인 - 객체의 양방향 관계

이렇게 되어버리면 jpa가 member객체의 team값이 바뀌었을때 업데이트를 하는지 

Team객체의 members의 값이 바뀌었을때 업데이트를 해야 되는지 딜레마가 옵니다.

그래서 룰이 하나 생깁니다.

둘중 하나를 연관관계의 주인으로 정해야 한다!

 

연관관계의 주인(Owner)

양방향 매핑 규칙

  • 객체의 두 관계중 하나를 연관관계의 주인으로 지정(Member의 team 이나 Team의 members)
  • 연관관계의 주인만이 외래키를 관리(등록,수정 할 수 있다)
  • 주인이 아닌쪽은 읽기만 가능
  • 주인은 mappedBy 속성을 사용하면 안됩니다.
  • 주인이 아니면 mappedBy 속성으로 주인을 지정해줘야 합니다.

 

누구를 주인으로 ?

외래 키가 있는 곳을 주인으로 정해주어야 합니다.

[JPA] 양방향 연관관계와 연관관계의 주인 - 누구를 주인으로 ?

위 그림을 보면 Member N : 1 Team 이고 FK : PK 입니다.

그러면 Team에는 @OneToMany 어노테이션이 걸리겠죠? Team에있는 members를 mappedBy속성을 사용하고 

주인으로 Member의 team이라고 @OneToMany(mappedBy="team")이라고 지정해줘야 합니다.

 

N:1에서 1쪽을 연관관계의 주인으로 지정할때 문제

팀의 멤버스의 값을 바꿨으면 다른테이블에 업데이트가 나갑니다.

이러면 jpa를 진짜 잘하면 이해하겠지만 team의 값을 바꿨는데 member테이블에 업데이트쿼리가 나가면 이게 왜나가지?..라는 의문과 함께 돌아오지못하는 강을 건너게 됩니다...또 나중에 성능 문제로까지 이어질 수 있습니다.

Member를 인서트하면 TEAM_ID가 FK이므로 한방쿼리로 할 수 있지만 team에 인서트가 나가면 member에 업데이트쿼리가 나가는 관계가 있을수도 있기 때문에  다대일관계에서는 외래키가 있는곳으로 주인을 정해라 와이?

DB입장에서 보면 외래키가있는곳이 무조건 다이고 없는곳이 1이다. 그 말인즉슨, DB의 N쪽이 연관관계의 주인이고 

엔티티에서 @ToOne을 적는쪽, N쪽(외래키가 있는곳)이 무조건 연관관계의 주인이 됩니다.

자동차와 바퀴가있으면 연관관계의 주인은 바퀴로 줘야합니다. 이렇게해야 성능이슈도없고 설계도 깔끔하게 된다고 합니다는 영한님의 말씀...!입니다.요 기준만 잡으면 연관관계매핑이 어렵지않습니다.

728x90

'JPA' 카테고리의 다른 글

[JPA] 다양한 연관 관계 매핑  (0) 2022.06.18
[JPA] 양방향 연관관계와 연관관계의 주인2- 주의점,정리  (0) 2022.06.18
[JPA] 필드와 컬럼 매핑  (0) 2022.06.14
[JPA] 플러시란?  (0) 2022.06.13
[JPA] 영속성 컨텍스트  (0) 2022.05.11

댓글