Computer Science/Spring & Java

[JPA]스프링 연관관계 매핑

콩순이냉장고 2022. 10. 23. 19:03

 

단방향 연관관계

  • 회원과 팀이있다.
  • 회원은 하나의 팀에만 소속될수 있다.
  • 회원과 팀은 다대일 관계

 

 

객체중심으로 볼때

객체 연관관계

회원객체와 팀 객체는 단방향 관계 , 회원은 Member.team 필드를 통해서 팀을 알수있지만 반대로 팀은 회원을 알수 없음.

member -> team의 조회는 member.getTeam()으로 가능, 반대 방향인 team ->member는 접근 할수가없음

 

 

테이블 중심으로 볼때

회원 테이블과 팀 테이블은 양방향 관계, TEAM_ID로 외래키를 통해 회원가 툄을 조인, 반대로 팀과 회원도 조인 가능

 

 

객체를 테이블에 맞춰서 모델링을 하게되면

• 테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다. 
• 객체는 참조를 사용해서 연관된 객체를 찾는다. 
• 테이블과 객체 사이에는 이런 큰 간격이 있다

 

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

 

//조회
 Member findMember = em.find(Member.class, member.getId()); 
 //연관관계가 없음
 Team findTeam = em.find(Team.class, team.getId());

식별자로 다시 조회하게됨 ,객체지향적이지 않음

 

 

 

객체 지향 모델링 (객체의 참조와 테이블의 외래키를 매핑)

 

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

 

ORM 매핑

 

//조회
 Member findMember = em.find(Member.class, member.getId()); 
//참조를 사용해서 연관관계 조회
 Team findTeam = findMember.getTeam();

참조로 연관관계를 조회 - 객체 그래프 탐색

 

 

객체 연관관계와 테이블 연관과계의 가장 큰차이

객체간에 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가해서 참조해야함, 결국 연관관계를 하나 더 만들어야함 , 객체에선 서로 서로 참조하는것을 양방향 관계 ,따지고 보면 양방향 관계가 아니라 서로다른 단방향 관계가 2개인 것임 , 테이블은 외래키 하나로 양방향으로 조인가능

 

객체 연관관계 vs 테이블 연관관계

  • 객체는 참조로 연관관계를 맺음
  • 테이블은 외래키로 연관관계를 맺음

 

참조를 사용하는 객체의 연관관계는 단방향

  • A → B (a.b)

 

객체를 양방향으로 참조하려면 단방향 연관관계 2개를 만듦

  • A → B (a.b)
  • B →  A (b.a)

 

외래키를 사용하는 테이블의 연관관계는 양방향

  • A JOIN B 가 가능하면 반대로 B JOIN A도 가능

 

 

 

양방향 연관관계, 연관관계 주인

 

 

 

양방향 매핑

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

 

 

객체는 양방향 관계라는것이 없음, 서로다른 단방향 연관관계 2개를 양방향인것처럼 보이게 할뿐

 

객체 연관관계

회원 → 팀 연관관계 1개(단방향)

팀 → 회원 연관관계 1개(단방향)

class A {
 B b; 
}
class B {
 A a;
}

테이블 연관관계

회원 ↔ 팀 연관관계 1개(양방향)

 

MEMBER.TEAM_ID 외래키 하나로 양방향 연관관계를 가짐 (양쪽으로 조인 가능)

SELECT * 
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID 
SELECT * 
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID

 

 

테이블은 외래키 하나로 두 테이블의 연관관계를 관리 , 엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이참조로 외래키를 관리하면됨, 그러나 양방향으로 매핑하면

회원 -> 팀, 팀-> 회원 두곳에서 서로를 참조, 따라서 객체의 연관관계를 관리하는 포인트는 2곳으로 늘어남.

 

엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래키는 하나임, 따라서 둘차이가 발생하기때문에 외래키를 관리 해야함

이런차이로 인해 JPA는 두객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야함 이것을  연관관계의 주인(Owner)이라 함

 

 

연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록,수정,삭제) 할수 있음, 반면에 주인인 아닌 쪽은 읽기만 가능

  • 주인은 mappedBy 속성을 사용x
  • 주인이 아닌쪽은 amppedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정

 

 

외래 키가 있는 있는 곳을 주인으로 정해라
여기서는 Member.team이 연관관계의 주인

 

양방향 매핑시  연관관계의 주인에 값을 입력

 

Team team = new Team();
 team.setName("TeamA");
 em.persist(team);
 Member member = new Member();
 member.setName("member1");
 team.getMembers().add(member); 
 //연관관계의 주인에 값 설정
 member.setTeam(team); //**
 em.persist(member);

 

단방향 매핑만으로도 이미 연관관계 매핑은 완료
• 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추
가된 것 뿐
• JPQL에서 역방향으로 탐색할 일이 많음
• 단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨
(테이블에 영향을 주지 않음)