JPA
지연로딩, 즉시로딩
91cm
2021. 8. 22. 21:56
Team과 Member의 관계가 1:N이고
member를 조회 할 때 member만 사용하는대 Team까지 가져오면 비용적 손해다.
그럴 경우 LAZY로딩을 이용해 proxy로 조회하는 방법을 쓰면된다.
ex) @ManyToOne(fetch = FetchType.LAZY) // 지연로딩
주의사항
1.기본은 모두 LAZY로딩으로 잡아 놓고, 필요한 부분만 EAGER로딩으로 변경하는 것을 권장하고 있다.
이유
1-1 JPQL로 작성시 N+1 이슈발생.
1-2 다른 팀원이 member만 조회하려고 findById를 날렸는대, team 쿼리까지나가면 당황.
2. 연관관계 별로 fetch 기본값이 다름.
@ManyToOne -> EAGER
@OneToOne -> EAGER
@ManyToMany -> LAZY
@OneToMany -> LAZY
@Entity
@Setter @Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "name"})
public class Team {
@Id @GeneratedValue
@Column(name = "team_id")
private long id;
private String name ;
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<>();
public Team(String name) {
this.name = name;
}
}
package study.datajap.entity;
import lombok.*;
import javax.persistence.*;
@Entity
@Setter @Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "username", "age"})
public class Member extends BaseEntity{
@Id @GeneratedValue
private long id;
private String username;
private int age;
@ManyToOne(fetch = FetchType.LAZY) // 지연로딩
@JoinColumn(name = "team_id")
private Team team;
public Member(String username) {
this.username = username;
}
public Member(String username, int age, Team team) {
this.username = username;
this.age = age;
if(team != null){
changeTeam(team);
}
}
public Member(String username, int age) {
this.username = username;
this.age = age;
}
public void changeTeam(Team team){
this.team = team ;
team.getMembers().add(this);
}
}
@Test
public void 지연로딩 () {
Optional<Member> byId = memberRepository.findById(2L); // fetch = FetchType.EAGER OR LAZY
// byId.get().getTeam() // 호출 시점에 Team 쿼리 날림
}
Hibernate:
select
member0_.id as id1_1_,
member0_.reg_date as reg_date2_1_,
member0_.update_date as update_d3_1_,
member0_.reg_user_id as reg_user4_1_,
member0_.update_user_id as update_u5_1_,
member0_.age as age6_1_,
member0_.team_id as team_id8_1_,
member0_.username as username7_1_
from
member member0_
where
member0_.username=?
즉시로딩으로 변경할 경우 join된 쿼리가 날라가게 된다.
@ManyToOne(fetch = FetchType.EAGER) // 즉시로딩
@JoinColumn(name = "team_id")
private Team team;
public Member(String username) {
this.username = username;
}
Hibernate:
select
member0_.id as id1_1_0_,
member0_.reg_date as reg_date2_1_0_,
member0_.update_date as update_d3_1_0_,
member0_.reg_user_id as reg_user4_1_0_,
member0_.update_user_id as update_u5_1_0_,
member0_.age as age6_1_0_,
member0_.team_id as team_id8_1_0_,
member0_.username as username7_1_0_,
team1_.team_id as team_id1_2_1_,
team1_.name as name2_2_1_
from
member member0_
left outer join
team team1_
on member0_.team_id=team1_.team_id
where
member0_.id=?
그러면 모든 연관관계를 LAZY로딩으로 바꾸었다가, 특정한 곳에서 member,team을 동시에 조회 하는 경우가 생긴다면???
-> JPQL의 패치 조인을 사용하거나 , @Entitygraph를 사용하면 된다!