[Spring Boot]/[JPA]

[JPA] 연관관계 매핑 정리

북방바다코끼리표범 2023. 10. 25. 22:02

복습

https://shins99.tistory.com/113

 

[JPA] 양방향과 단방향 매핑, 연관관계의 주인(mappedBy)

복습 http://shins99.tistory.com/112 [JPA] 기본 키(primary key)와 매핑 복습 https://shins99.tistory.com/111 [Spring Boot] 페이징(paging) 복습 https://shins99.tistory.com/109 [JPA] 영속성 컨텍스트 영속성 컨텍스트란? 영속성

shins99.tistory.com


@ManyToOne 다대일 (N : 1) 매핑

- 연관관계 매핑 시 가장 많이 사용하는 매핑 방법

- 다대일은 외래키(FK)를 갖고 있는 "다"쪽이 연관관계의 주인

 

단방향 매핑
 
@Entity
 
public class Member {
 
 
 
@Id @GeneratedValue
 
@Column(name = "MEMBER_ID")
 
private Long id;
 
 
 
private String username;
 
 
 
@ManyToOne
 
@JoinColumn(name = "TEAM_ID")
 
private Team team;
 
...
 
}

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

@JoinColumn을 어노테이션을 통해 참조할 객체의 왜래키(FK)의 이름을 지정한다.

 

양방향 매핑

- 단방향 일 경우 Team 엔티티에서는 Member 엔티티의 필드 값 조회 불가능

- Team 엔티티에서도 Member 엔티티의 필드 값 조회가 필요할 시

   아래처럼 Team 엔티티에서 mappedBy로 연관관계 매핑 주인을 지정해야 함

 
public class Team {
 
@Id @GeneratedValue
 
private Long id;
 
 
 
private String name;
 
 
 
@OneToMany(mappedBy = "team")
 
private List<Member> member;
 
...
 
}

@OneToMany - 일대다 (1 : N) 매핑

- 객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조

- 다대일의 반대구조 일대다는 "일"이 연관관계의 주인이 되고, "다" 쪽에 외래키(FK) 존재

 

 
@Entity
 
public class Member {
 
 
 
@Id
 
@GeneratedValue
 
@Column(name = "MEMBER_ID")
 
private Long id;
 
 
 
@Column(name = "USERNAME")
 
private String username;
 
...
 
}

 
public class Team {
 
@Id @GeneratedValue
 
private Long id;
 
 
 
private String name;
 
 
 
@OneToMany(mappedBy = "team")
 
@JoinColumn(name = "TEAM_ID")
 
private List<Member> member;
 
...
 
}

 

일대다 매핑 단점
  • 엔티티가 관리하는 외래 키가 다른 테이블에 있다. (구조가 비정상적)
  • 연관관계 관리를 위해 추가로 UPDATE 쿼리를 실행한다

일대다 단항향 매핑보다는 "다대일 양방향 매핑"을 사용하는 것을 권장 


@OneToOne  일대일 (1 : 1) 매핑

- 주 테이블이나 대상 테이블 중에 외래키(FK)를 상황에 맞게 선택하면 됨

  주 테이블에 외래키를 둘 경우 대상 테이블에 외래 키를 둘 경우
특징 주 객체가 대상 객체의 참조를 가지는 것 처럼
주 테이블에 외래 키를 두고 대상 테이블을 찾는다.
대상 테이블에 외래 키가 존재
장점 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능

주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
단점 값이 없으면 외래 키에 null 허용 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩된다.

 

매핑 방식은 다대일과 동일 @ManyToOne 대신 @OneToOne 매핑방식 사용

단방향 매핑
 
@Entity
 
public class Member {
 
 
 
@Id @GeneratedValue
 
@Column(name = "MEMBER_ID")
 
private Long id;
 
 
 
private String username;
 
 
 
@OneToOne
 
@JoinColumn(name = "TEAM_ID")
 
private Team team;
 
...
 
}

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

 

양방향 매핑

- 다대일 양방향 매핑 처럼 외래키가 있는 곳이 연관관계 주인

(반대편은 mappedBy를 적용)

 
@Entity
 
public class Team {
 
 
 
@Id @GeneratedValue
 
@Column(name = "TEAM_ID")
 
private Long id;
 
 
 
private String name;
 
 
 
@OneToOne(mappedBy = "team")
 
private Member member;
 
...
 
}

 


@ManyToMany 다대다 (N : N) 매핑

 

- 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현 불가능

- 아래 처럼 연결 테이블을 추가해서 일대다 또는 다대일 관계로 풀어내야 함

특징 : 연결 테이블용 엔티티 추가하고 @JoinTable로 연결 테이블을 지정

 

 
@Entity
 
public class MemberTeam {
 
@Id @GeneratedValue
 
private Long id;
 
 
 
@ManyToOne
 
@JoinColumn(name = "MEMBER_ID")
 
private Member member;
 
 
 
@ManyToOne
 
@JoinColumn(name = "TEAM_ID")
 
private Team team;
 
...
 
}

 

Member와 Team을 연결 테이블에 대해 @OneToMany 일대다 연관관계로 매핑하면 다대다 연관관계가 됨

 
@Entity
 
public class Member {
 
@Id @GeneratedValue
 
private Long id;
 
 
 
private String name;
 
 
 
@OneToMany(mappedBy = "member")
 
private List<MemberTeam> teams;
 
...
 
}

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

 

다대다 사용은 권장하지 않음

- 다대다 매핑은 실무에서 잘 사용하지 않음

  • 연결 테이블이 단순히 연결만 하고 끝나지 않음
  • 중간 테이블에는 매핑정보만 들어가고 추가 데이터를 넣는 것이 불가능
  • 중간 테이블이 숨겨져 있기 때문에 쿼리가 예상하지 못하는 형태로 나감
  • 실무 비즈니스는 복잡해서 ManyToMany로 풀 수있는게 거의 없음