JPA

[JPA] 지연 로딩

syj0522 2024. 9. 12. 12:35

JPA는 데이터를 조회할 때 즉시 로딩(EAGER)와 지연 로딩(LAZY) 두 가지 방식을 사용합니다. 간단히 설명하면 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고, 지연 로딩은 필요한 시점에 연관된 데이터를 불러오는 것입니다.

 

Fetch Type

Fetch Type이란 JPA가 엔티티를 조회할 때 연관관계에 있는 객체들을 어떻게 가져올 것이냐를 나타내는 설정값입니다.

 

JPA를 사용하면 엔티티 조회가 발생할 때 JPA가 알아서 JPQL을 이용해 쿼리문을 생성합니다. 이때 객체와 필드를 보고 쿼리를 생성하는데, 만약 @ManyToOne 또는 @OneToMany와 같이 다른 객체와 연관관계 매핑이 되어있으면 그 객체들까지 조회하게 됩니다. 이때 이 객체를 어떻게 불러올 것인지 @xxToxx(fetch = Fetch Type.LAZY)형태로 설정할 수 있습니다. 

 

fetch의 디폴트값은 @xxToOne에서는 EAGER, @xxToMany에서는 LAZY입니다.

 

지연로딩(LAZY)

FetchType으로 LAZY를 줬습니다. 따라서 Member을 조회하면, Member을 조회하는 시점이 아닌 실제 Team을 사용하는 시점에 Team을 조회하는 쿼리가 실행됩니다.

@Entity
public class Member {

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

    @ManyToOne(fetch = FetchType.LAZY) //지연로딩 설정
    @JoinColumn(name = "team_id")
    Team team;
}

@Entity
public class Team {

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

Member을 조회할 때 JPA가 만드는 JPQL입니다.

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

실제 쿼리를 보면 Team을 조회하는 쿼리는 아직 실행되지 않았습니다.

select
    member0_.id as id1_0_,
    member0_.team_id as team_id3_0_,
    member0_.username as username2_0_ 
from
    Member member0_

이 방법이 유용한 이유는, 쓸 데 없는 쿼리 호출을 줄일 수 있기 때문입니다.

만약 멤버 1명 당 팀이 1000개였다면 지연로딩을 쓰지 않는 경우 멤버 한 명을 조회할 때마다 팀 1000개를 찾는 쿼리가 무조건 실행됩니다. 반면 지연로딩을 쓰는 경우 멤버의 팀 필드를 실제로 사용할 때만 팀을 조회하는 쿼리가 실행됩니다. 지연로딩을 쓰고 안 쓰고에 의해 성능 차이가 굉장할 것 같습니다.