DOing
[JPA] Fetch - 즉시 로딩, 지연 로딩 본문
⌚ 지연 로딩(FetchType.LAZY)
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.EAGER) // 지연로딩 : 프록시객체
@JoinColumn(name = "TEAM_ID")
private Team team;
..
}
- Entity를 처음 생성할때
- 실제로 객체를 조회할때
Team team = member.getTeam();
team.getName(); // 실제 team을 사용하는 시점에 프록시 초기화 이때 쿼리가 나간다.
단순히 getTeam()으로 가져올 때가 아니고 team에 있는 무언가를 실제 사용할때 초기화된다!
⌚ 즉시 로딩(FetchType.EAGER)
@Entity
public class Member {
@Id
@GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne(fetch = FetchType.EAGER) // 지연로딩 : 프록시객체
@JoinColumn(name = "TEAM_ID")
private Team team;
..
}
: Member를 로딩할때 Team까지 조인해서 가져온다.
⌚ 지연 로딩 VS 즉시 로딩
가급적 지연로딩만 사용해야한다!!! 특히 실무에서와 같이 테이블이 복잡하게 얽혀있는 경우에는 지연로딩을 사용해야한다. 그이유는 다음과 같다.
1. 즉시로딩을 사용하면 예상하지 못한 SQL이 발생한다.
-> 사실 이 이슈는 내가 진행하던 프로젝트에서 발생했었다. (실제 프로젝트 이슈)
2. 즉시로딩은 JPQL에서 N+1 문제를 일으킨다.
⌚ 즉시 로딩의 N+1 문제
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
// JPQL은 그대로 SQL로 번역이된다.
// 즉 Member만 일단 SELECT한다.
// Member 다가져왔는데 EARGER러구...? Team을 다시 가져올게!
// SQL 1 : select * from Member
// SQL N : select * from Team where TEAM_ID = xxx
쿼리를 하나를 날렸는데 N개가 딸려올 수 있다. 실무에서는 JPQL을 많이 사용하고 이러한 문제가 많이 발생한다고 한다.
이 문제를 해결하기 위해서는 모든 연관관계를 일단 지연로딩으로 해야한다.
그러고 정말 필요해서 같이 조인해야한다면, Fetchjoin 이라는 동적으로 원하는 쿼리들을 한번에 가져올 수 있다.
List<Member> members = em.createQuery("select m from Member m join fetch m.team", Member.class).getResultList();
⌚ fetch 기본값
1. @ManyToOne, @OneToOne은 기본이 즉시 로딩-> LAZY로 설정
2. @OneToMany, @ManyToMany는 기본이 지연 로딩
'JPA' 카테고리의 다른 글
Querydsl이란? (0) | 2021.08.04 |
---|---|
[JPA] 연속성 전이(CASCADE) (0) | 2021.07.15 |
[JPA] 영속성 컨텍스트3 - 플러시 (0) | 2021.07.14 |
[JPA] 영속성 컨텍스트2 - 영속성 컨텍스트의 이점 (0) | 2021.07.14 |
[JPA] 영속성 컨텍스트1 - 엔티티 생명주기 (0) | 2021.07.14 |