[JPA 기본] 즉시 로딩(EAGER) vs 지연 로딩(LAZY)

강신현·2022년 7월 18일
0

✅ fetch = FetchType.LAZY ✅ fetch = FetchType.EAGER

필요성

다음 두가지 경우가 있다고 해보자

  1. 회원과 팀 함께 출력
public void printUserAndTeam(String memberId) {
	Member member = em.find(Member.class, memberId);
	Team team = member.getTeam();
	System.out.println("회원 이름: " + member.getUsername());
	System.out.println("소속팀: " + team.getName());
}
  1. 회원만 출력
public void printUser(String memberId) {
	Member member = em.find(Member.class, memberId);
	Team team = member.getTeam();
	System.out.println("회원 이름: " + member.getUsername());
}

회원과 팀을 항상 함께 출력한다면 문제가 되지 않지만
회원만 출력하는 경우에는 팀까지 불러올 필요가 없으므로 낭비가 생긴다.

이를 해결하기 위해 jpa에서 프록시지연로딩을 지원한다.

지연 로딩 (LAZY)

Member와 Team을 자주 함께 사용하지 않는 경우
실제 사용하는 경우에만 초기화를 하여 낭비를 줄임

Member select 쿼리는 있고 Team을 사용하는 경우에만 Team select 쿼리 날림
1 (+1)

  • Member
@Entity
public class Member extends BaseEntity{

	...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}
  • Main
Team team = new Team();
team.setName("teamA");
em.persist(team);

Member member1 = new Member();
member1.setUsername("user1");
member1.setTeam(team);
em.persist(member1);

em.flush();
em.clear();

Member m = em.find(Member.class, member1.getId());
System.out.println("m = " + m.getTeam().getClass()); // proxy(가짜)

m.getTeam().getName(); // 초기화 (이때 쿼리 날라감)

즉시 로딩 (EAGER)

Member와 Team을 자주 함께 사용하는 경우

굳이 지연 로딩 (LAZY)을 사용하여 쿼리를 2번에 나눠 날릴 필요가 없음

  • Member
@Entity
public class Member extends BaseEntity{

	...

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}
  • Main
Team team = new Team();
team.setName("teamA");
em.persist(team);

Member member1 = new Member();
member1.setUsername("user1");
member1.setTeam(team);
em.persist(member1);

em.flush();
em.clear();

Member m = em.find(Member.class, member1.getId()); // Member 와 Team 을 join 하여 한번에 다 가져옴
System.out.println("m = " + m.getTeam().getClass()); // proxy(가짜)가 아니라 team.class(진짜)로 뜸

m.getTeam().getName();

주의

🔥 가급적 지연 로딩(LAZY)만 사용 (실무)
한방에 가져와야 할 경우에 JPQL - join fetch 사용함

  • 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
  • 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
    JPA에서는 한방에 가져오지만,
    JPQL에서는 2개 쿼리를 사용하여 가져온다.

결론

@ManyToOne, @OneToOne : 기본이 즉시 로딩(EAGER) -> 지연 로딩(LAZY)으로 해줘야 함
@OneToMany, @ManyToMany : 기본이 지연 로딩(LAZY)

profile
땅콩의 모험 (server)

0개의 댓글