2021. 2. 11. 16:23ㆍ프로그래밍 언어/Spring Framework
[인프런 김영한] JPA - 즉시로딩 / 지연로딩
해당 글은 인프런 김영한강사님의 영상을 보고 정리한 글입니다.
Spring Boot, Spring Data JPA를 사용해 실습하였습니다.
김영한 인프런 : www.inflearn.com/users/@yh
▣ Member를 조회할 때 Team을 함께 조회해야 할까?
-> 지연로딩(Lazy)을 지원한다.
▣ Member와 Team중에서 Member만 자주 조회한다면 - Lazy / 지연로딩
Member
@Entity
public class Member{
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
Team
@Entity
public class Team{
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
List<Member> members = new ArrayList<>();
}
실행
Member member = new Member();
member.setName("user1");
memberRepository.save(member);
// Member를 조회하면 select에 Team까지 Join문 쿼리가 출력된다.
// Member를 조회하면 select에 Team까지 Join문 쿼리가 출력된다.
// @ManyToOne
// @JoinColumn(name = "TEAM_ID")
// private Team team;
Member findMember = memberRepository.findById(member.getId()).get();
System.out.println(findMember.getId());
System.out.println(findMember.getName());
// 실행결과
Hibernate:
select
member0_.member_id as member_i1_0_0_,
member0_.name as name2_0_0_,
member0_.team_id as team_id3_0_0_,
team1_.team_id as team_id1_1_1_,
team1_.name as name2_1_1_
from
member member0_
left outer join
team team1_
on member0_.team_id=team1_.team_id
where
member0_.member_id=?
| Member만 조회하고 싶은데 Team까지 join해서 가지고 온다.
◈ 수정
Member
@Entity
public class Member{
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
}
| Team의 ManyToOne은 기본적으로 FetchType.EAGER를 사용하는데 이걸 FetchType.LAZY로 변경하게 되면
Member 클래스만 DB에서 조회한다.
Member member = new Member();
member.setName("user1");
memberRepository.save(member);
// FetchType.LAZY를 설정하면 Member만 조회한다.
// @ManyToOne(fetch = FetchType.LAZY)
// @JoinColumn(name = "TEAM_ID")
// private Team team;
Member findMember = memberRepository.findById(member.getId()).get();
System.out.println(findMember.getId());
System.out.println(findMember.getName());
// 실행 결과
Hibernate:
select
member0_.member_id as member_i1_0_0_,
member0_.name as name2_0_0_,
member0_.team_id as team_id3_0_0_
from
member member0_
where
member0_.member_id=?
| Select 쿼리를 보면 member만 가지고 오는것을 볼 수 있다.
◈ Lazy로 설정 했을 때, Team은 어떻게 가져올까?
Team team = new Team();
team.setName("team1");
teamRepository.save(team);
Member member = new Member();
member.setName("user1");
member.setTeam(team);
memberRepository.save(member);
// @ManyToOne(fetch = FetchType.LAZY)
Member findMember = memberRepository.findById(member.getId()).get();
System.out.println(findMember.getId());
System.out.println(findMember.getName());
// 그러면 필요할 때만 가지고 오고 싶어할 때 프록시를 생각하면 된다.
System.out.println("findMember.class = " + findMember.getTeam().getClass());
System.out.println("=========================================");
System.out.println("getName : " + findMember.getTeam().getName());
// 실행결과 , 프록시로 가지고 오는것을 볼 수 있다.
findMember.class = class com.spring.jpa.Team$HibernateProxy$YcSewtkv
| 처음 member를 find()했을 때는 Team을 프록시로 조회하며 실제 member.getTeam()을 하는 시점에 DB조회
▣ Member와 Team을 자주 함께 사용한다면? - EAGER / 즉시로딩
Member
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "TEAM_ID")
private Team team;
// 실행 결과
Hibernate:
select
member0_.member_id as member_i1_0_0_,
member0_.name as name2_0_0_,
member0_.team_id as team_id3_0_0_,
team1_.team_id as team_id1_1_1_,
team1_.name as name2_1_1_
from
member member0_
left outer join
team team1_
on member0_.team_id=team1_.team_id
where
member0_.member_id=?
// 프록시 조회가 아니다.!!
findMember.class = class com.spring.jpa.Team
| 즉시로딩은 한번에 다 조회를 해서 가지고오기 때문에 프록시를 사용하지 않는다.
▣ 지연로딩, 즉시로딩에 대한 김영한님의 Point!
현제 예제는 2개의 테이블이여서 지금은 상관 없지만. 실무에서는 한번 조회할 때 다수의 테이블(대략 5개 이상)을 조인해서 가지고 오면 성능문제를 일으킨다
* 가급적 지연 로딩만 사용(특히나 실무에서는)
- 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
- 즉시로딩은 JPQL에서 N+1문제를 일으킨다.
em.creatQuery("select m from Member m", Member.class).getResultList()
// 실행결과 2개의 SQL문이 출력된다.
select문에서 Member를 조회하지만 Member안에 Team이 FK로 있기 때문에 Team도 조회하면서 총 2번의 쿼리 출력
* ManyToOne, @OneToOne은 기본이 즉시로딩. -> LAZY로 설정하기.
- @OneToMany, @ManyToMany는 기본이 지연로딩.
'프로그래밍 언어 > Spring Framework' 카테고리의 다른 글
[인프런 김영한] JPA - 임베디드 타입(복합 값 타입) (0) | 2021.02.12 |
---|---|
[인프런 김영한] JPA - 영속성전이(CASCADE) (0) | 2021.02.11 |
[인프런 김영한] JPA - 프록시 (0) | 2021.02.10 |
[인프런 김영한] JPA - @MappedSuperclass (0) | 2021.02.09 |
[인프런 김영한] JPA - 상속관계 매핑 (0) | 2021.02.09 |