[JPA] OneToOne 연관관계 (mappedby / fetchType)
매일같이 사용해도 매일같이 헷갈리는 연관관계를 다시 정리해봤다.
OneToOne 연관관계는 오직 서로가 하나뿐인 1:1 관계를 말하고 이 둘은 FK로 연결되어 있다.
OneToOne 연관관계의 특징을 알아보기 위해 엔티티를 만들어줬다.
하나는 Student 엔티티이고
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Student {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne
private Passport passport;
public Student(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("Student[%s]", name);
}
}
|
cs |
또 다른 하나는 Passport 엔티티이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Passport {
@Id
@GeneratedValue
private Long id;
private String number;
@OneToOne
private Student student;
public Passport(String number) {
this.number = number;
}
@Override
public String toString() {
return String.format("Passport[%s]", number);
}
}
|
cs |
실습을 위한 간단한 데이터도 미리 넣어준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
insert into passport(id,number)
values(40001,'E123456');
insert into passport(id,number)
values(40002,'N123457');
insert into passport(id,number)
values(40003,'L123890');
insert into student(id,name, passport_id)
values(20001,'한소희', 40001);
insert into student(id,name, passport_id)
values(20002,'아이유', 40002);
insert into student(id,name, passport_id)
values(20003,'김태리', 40003);
|
cs |
연관관계 주인 설정
이대로 서버를 실행하면
엔티티 둘다 관계를 가지는 FK 가 생성되는 것을 볼 수 있다.
하지만 이렇게 되면 데이터가 중복되기 때문에 별로 좋아보이지 않는다.
이 중복을 제거하기 위해 연관관계의 주인을 정의해준다.
mappedBy = "연관관계의 주인"
그리고 서버를 시작하면 연관관계의 주인인 passport의 id가 FK로 정의되어 생성된 걸 확인할 수 있다.
Fetch.Type
OneToOne 연관관계에서는 fetch join의 default가 Eager이다.
즉 한쪽의 데이터를 조회해도 다른 쪽의 데이터가 같이 가져와진다는 것이다.
간단히 findById를 통해 가져온 Student를 로그로 찍어보는 테스트를 진행했다.
🛑 둘다 정의 안함 (Default Eager)
둘다 정의 안한 디폴트 상황일때 OneToOne 연관관계는 fetch.Type을 Eager를 갖는다.
테스트를 실행해보면 left outer join을 통해 student와 passport를 조인해와 해당 학생의 passport 정보를 뿌려준다.
학생 id 20001 의 passport number은 E123456 이다.
잘 가져온 걸 볼 수 있다.
🛑 Passport 연관관계의 주인, FetchType.LAZY
위에 모두 Eager일때와 같다.
🛑 Student FetchType.LAZY
이렇게 되면 select 쿼리를 두번 날린다.
Student에서 Passport와의 관계를 LAZY로 정의했기때문에
Student에서 select할 때 join하지 않는다.
하지만 Passport에서는 default = Eager 상태이기 때문에
뒤이어 Passport에서 Student로 조인해 해당 student의 FK로 연결된 passport_id를 가져온다.
🛑 둘다 Lazy
이 경우에는 각각의 테이블로 두번 select 요청을 보내어
학생 id에 해당하는 학생의 passport id를 가져와 passport 정보를 가져온다.
각각 설정만 다르게 해줘도 요청의 결과가 달라진다.
코드
GitHub - recordbuffer/TIL: Today I Learned
Today I Learned. Contribute to recordbuffer/TIL development by creating an account on GitHub.
github.com
참고
Master Hibernate and JPA with Spring Boot in 100 Steps
Learn Hibernate, JPA (Java Persistence API) and Spring Data JPA using Spring and Spring Boot
www.udemy.com
자바 ORM 표준 JPA 프로그래밍 | 김영한 - 교보문고
자바 ORM 표준 JPA 프로그래밍 | 자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA
product.kyobobook.co.kr