본문 바로가기
[Spring Boot]/[JPA]

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

by 북방바다코끼리표범 2023. 10. 24.

복습

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


양방향, 단방향 매핑

 

  • 양방향 : 두 객체 모두가 각각 참조용 필드를 갖고 참조
  • 단방향 : 두 객체 사이에 하나의 객체만 참조용 필드를 갖고 참조

 

데이터베이스에서 양방향과 단반향

 

- 데이터베이스에는 양방향과 단방향이라는 개념 없음

- 외래키(FK) 하나면 양쪽의 연관관계를 알 수 있음 (양방향 관계의 특성을 가짐)

                위의  ERD 관계도에서는 TEAM_ID 라는 외래키 하나로 원하는 값 조회 가능

 

N : 1 관계

- 데이터 베이스 테이블은 외래키(FK) 하나로 양쪽 테이블을 조인하여 두 테이블의 연관관계를 관리

 

 
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

 

 

객체에서 양방향과 단방향

 

- 객체는 참조용 필드가 있는 객체만 다른 객체를 참조하는 것이 가능

 

단방향 관계

- Member 엔티티는 Team 엔티티의 클래스를 필드로 갖고 있음

- Member 엔티티는 Team 엔티티의 모든 필드 조회가능

- Team 엔티티는 Member 엔티티의 필드를 조회할 수 없음

 

 

양방향 관계

- Member 엔티티는 Team 엔티티의 클래스를 필드로 갖고 있음

- Team 엔티티의 여러 멤버는 하나의 팀에 속할 수 있는 다 : 1 관계이므로 Member타입을 갖는 List를 필드로 가짐

- 두 엔티티가 서로 참조용 필드를 갖고 있기 때문에 양쪽에서 필요한 모든 필드 조회 가능

(연관관계 주인을 지정하는 mappedBy 옵션이 사용되었음)


패러다임의 차이 발생

-  패러다임의 차이는 단방향에서는 문제가 되지 않지만 양방향에서 문제가 발생함

- 데이터베이스는 외래 키 하나로 두 테이블이 연관관계를 맺음

- 객체의 양방향 관계는 A -> B, B -> A 로 참조가 2군데가 있음

 

- 패러다임의 차이를 해결하기 위해 양방향 매핑에서 객체의 두 관계 중 하나를 연관관계의 주인으로 지정해야 함

(연관관계의 주인이 있어야 객체 패러다임에서의 양방향 관계와 데이터베이스 패러다임에서 연관관계가 하나임을 보장할 수 있게 됨)

 

모두 양방향 관계만 사용하면 안되는 이유

- 객체 입장에서 양방향 매핑을 했을 때 양쪽으로 신경을 써야하기 때문에 오히려 복잡함

- 본적으로 단방향 매핑으로 하고 나중에 역방향으로 객체 탐색이 꼭 필요하다고 느낄 때 추가하는 것을 권장

 


연관관계의 주인 (mappedBy)

 

- 연관관계의 주인을 지정한다는 것 =

 객체의 두 관계 중 제어의 권한(데이터 조회, 저장, 수정, 삭제)를 갖는 실질적인 관계가 무엇인지 JPA에게 알리는 것

- 연관관계의 주인일 경우: 연관 관계를 갖는 두 객체 사이에서 조회, 저장, 수정, 삭제 가능

- 연관관계의 주인이 아닌 경우 : 주인이 아니면 조회만 가능

 

주인을 지정하는 기준

 

N : 1 관계

- 간단하게 주인은 외래 키가 있는 곳을 주인으로 지정함

 

양방향 매핑시 주의점

두 관계 양쪽에 값을 넣어주어야 한다.

- 순수한 객체 관계를 고려하면 항상 양쪽다 값을 세팅해야 함

 

N : 1 관계

- 만약 역방향(주인이 아닌 방향)만 연관관계 설정 하면 Member 테이블의 TEAM_ID는 null이 들어감

- Member가 연관관계의 주인이고, Team의 List<Member>는 mappedBy로 읽기 전용이기 때문

 

 
Team team = new Team();
 
team.setName("TeamA");
 
em.persist(team);
 
 
 
Member member = new Member();
 
member.setName("member1");
 
 
 
// 역방향(주인이 아닌 방향)만 연관관계 설정
 
team.getMembers().add(member);
 
 
 
em.persist(member);

 

- 역방향만 연관관계 설정 시 null 발생

 

-  양쪽에 값을 세팅해줘야 값이 정상적으로 들어감

 

 
Team team = new Team();
 
team.setName("TeamA");
 
em.persist(team);
 
 
 
Member member = new Member();
 
member.setUsername("member1");
 
member.addTeam(team); // 연관관계 편의 메서드 사용
 
em.persist(member);

 

양쪽 다 값을 세팅하기 위해 연관관계 편의 메서드를 생성하는 것을 권장

- 매번 양방향의 코드를 추가하기 힘들기 때문에 편의 메서드를 만들어 사용하는 것을 권장

 

 
@Entity
 
public class Member {
 
 
 
@Id
 
@GeneratedValue(strategy = GenerationType.IDENTITY)
 
@Column(name = "MEMBER_ID")
 
private Long id;
 
 
 
@Column(name = "USERNAME")
 
private String username;
 
 
 
@ManyToOne
 
@JoinColumn(name = "TEAM_ID")
 
private Team team;
 
 
 
// 연관관계 편의 메서드
 
public void addTeam(Team team) {
 
this.team = team;
 
team.getMembers().add(this);
 
}
 
 
 
... 생략
 
}
양방향 매핑시 무한 루프 주의
  • toString() 메서드나 Lombok을 한 쪽에서만 사용 하면 문제가 되진 않지만 양쪽에서 사용할 경우 무한 루프가 발생
  • JSON은 컨트롤러에서 엔티티를 반환하지 않고 Dto 객체를 따로 만들어서 반환하도록 해야 함

 

정리

- 단방향 매핑만으로도 이미 연관관계 매핑은 충분함
- 처음 설계시에는 단방향 매핑으로 설계를 하고 반대 방향으로 조회가 필요 할 때 추가하는게 나음 (테이블에 영향 X)

'[Spring Boot] > [JPA]' 카테고리의 다른 글

[JPA] 상속관계 매핑  (1) 2023.10.26
[JPA] 연관관계 매핑 정리  (1) 2023.10.25
[JPA] 기본 키(primary key)와 매핑  (38) 2023.10.23
[JPA] 페이징(paging)  (42) 2023.10.22
[JPA] 영속성 컨텍스트  (1) 2023.10.20