본문 바로가기
데이터베이스/JPA

JPA 지연로딩을 사용해야하는 이유, 지연로딩(Lazy)과 즉시로딩(Eager)

by jeonghaemin 2021. 2. 12.
728x90

공부하는 과정에서 작성한 글입니다. 잘못되거나 보충할 내용이 있다면 언제든지 알려주세요:)

JPA에서는 데이터를 조회할 때 즉시 로딩(EAGER)과 지연 로딩(LAZY) 두 가지 방식이 있다. 이 두 가지 방식을 간단하게 설명하면 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고, 지연 로딩은 필요한 시점에 연관된 데이터를 불러오는 것이라고 할 수 있다.

즉시 로딩(EAGER)

  • @xxToxx(fetch = fetchType.EAGER)

다음과 같이 Member 엔티티와 Team 엔티티가 N:1 매핑으로 관계를 맺고 있다.

@Entity
public class Member {

    @Id @GeneratedValue
    private Long id;
    private String username;

    @ManyToOne(fetch = FetchType.EAGER) //Team을 조회할 때 즉시로딩을 사용하곘다!
    @JoinColumn(name = "team_id")
    Team team;
}

@Entity
public class Team {

    @Id @GeneratedValue
    private Long id;
    private String teamname;
}

JPQL로 Member 1건 조회

Member findMember = em.createQuery("select m from Member m", Member.class).getSingleResult();

실제 SQL 코드

//멤버를 조회하는 쿼리
select
    member0_.id as id1_0_,
    member0_.team_id as team_id3_0_,
    member0_.username as username2_0_ 
from
    Member member0_

//팀을 조회하는 쿼리
select
    team0_.id as id1_3_0_,
    team0_.name as name2_3_0_ 
from
    Team team0_ 
where
    team0_.id=?

다음과 같이 즉시 로딩(EAGER) 방식을 사용하면 Member를 조회하는 시점에 바로 Team까지 불러오는 쿼리를 날려 한꺼번에 데이터를 불러오는 것을 볼 수 있다.

지연 로딩(LAZY)

  • @xxToxx(fetch = fetchType.LAZY)

아래와 같이 지연 로딩으로 설정하고 Member를 조회해보면 즉시 로딩 방식과 달리 Team을 조회하는 쿼리가 생성되지 않고 Member를 조회하는 쿼리만 나가고, 실제로 팀을 사용하는 시점에 Team을 조회하는 쿼리가 나간다.

 @ManyToOne(fetch = FetchType.LAZY) //Team을 조회할 때 지연로딩을 사용하곘다!
 @JoinColumn(name = "team_id")
 Team team;

JPQL로 Member조회

Member findMember = em.createQuery("select m from Member m", Member.class).getSingleResult();

실제 SQL 코드

//Team을 조회하는 쿼리가 나가지 않음!
select
    member0_.id as id1_0_,
    member0_.team_id as team_id3_0_,
    member0_.username as username2_0_ 
from
    Member member0_

지연 로딩을 사용하면 Member를 조회하는 시점이 아닌 실제 Team을 사용하는 시점에 쿼리가 나가도록 할 수 있다는 장점이 있다.

위 예제의 즉시 로딩에서는 Member와 연관된 Team이 1개여서 Team을 조회하는 쿼리가 1개 나갔지만, 만약 Member를 조회하는 JPQL을 날렸는데 연관된 Team이 1000개라면? Member를 조회하는 쿼리를 하나 날렸을 뿐인데 Team을 조회하는 SQL 쿼리 1000개가 추가로 나가게 된다.

그렇기 때문에 가급적이면 기본적으로 지연 로딩을 사용하는 것이 좋다.

참고로 fetch의 디폴트 값은 @xxToOne에서는 EAGER, @xxToMany에서는 LAZY이다.

참고

댓글