복습
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); |
양쪽 다 값을 세팅하기 위해 연관관계 편의 메서드를 생성하는 것을 권장
- 매번 양방향의 코드를 추가하기 힘들기 때문에 편의 메서드를 만들어 사용하는 것을 권장
|
|
|
public class Member { |
|
|
|
|
|
|
|
|
|
private Long id; |
|
|
|
|
|
private String username; |
|
|
|
|
|
|
|
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 |