연관관계(Mapping) - 즉시로딩(EAGER), 지연로딩(LAZY)

대영·2024년 1월 7일
2

Spring

목록 보기
7/15

🙏내용에 대한 피드백은 언제나 환영입니다!!🙏

앞 글에서 Mapping에 대한 개념과 사용 방법을 간단히 알아보았다.
이제 알아볼 것은 즉시로딩(EAGER), 지연로딩(LAZY)에 대해서 알아보겠다.

❕스프링 데이터 JPA로 엔티티 객체에 대한 CRUD는 JpaRepository를 상속하였다는 가정을 하겠다.

📌즉시로딩(EAGER), 지연로딩(LAZY)

참고!
@ManyToOne, @OneToOne
기본 값이 즉시 로딩이므로 지연 로딩으로 설정한다.
@OneToMany, @ManyToMany
기본 값이 지연 로딩이다.

👉즉시로딩(EAGER)

즉시로딩이란, 말 그대로 바로 로딩이 된다는 것이다.
즉시로딩을 하고자 한다면, 매핑 어노테이션에 fetch = FetchType.EAGER 속성을 추가해주면 된다.
아래의 코드는 앞 글에서 사용했던 Team(1:N), Member(N:1) Entity 클래스들이다.

@Getter
@Setter
@NoArgsConstructor
@Entity
public class Team {    // Team Entity
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team", fetch = FetchType.EAGER)
    private List<Member> members = new ArrayList<>();

    public Team(String name) {
        this.name = name;
    }
}

--------------------------------------------------------------------

@Getter
@Setter
@NoArgsConstructor
@Entity
public class Member {    // Member Entity
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "team_id")
    private Team team;

    public Member(String name) {
        this.name = name;
    }
}

위와 같이 즉시로딩이 될 수 있도록 fetch = FetchType.EAGER 속성을 달아주었다.

테스트를 위하여 데이터베이스에 1개의 Team과 그 팀에 속하는 1명의 Member를 추가했다고 하자.

memberRepository.findAll();

그리고, 위의 코드를 실행시키면,

Hibernate: 
    select
        m1_0.id,
        m1_0.name,
        m1_0.team_id 
    from
        member m1_0
Hibernate: 
    select
        t1_0.id,
        t1_0.name,
        m1_0.team_id,
        m1_0.id,
        m1_0.name 
    from
        team t1_0 
    left join
        member m1_0 
            on t1_0.id=m1_0.team_id 
    where
        t1_0.id=?

위와 같은 결과가 나온다.
데이터베이스에서 Member에 대한 값만 불러오고자 하였지만, Member과 매핑되어 있던 Team도 쿼리를 날려 불러온 것을 볼 수 있다.

👉지연로딩(LAZY)

그렇다면, Team에 대한 정보가 필요없다면, 지연로딩을 사용하면 된다.

지연로딩이란, 당장에 필요하지 않은 값은 호출하지 않고, 필요할 때 호출하겠다는 것이다.
지연로딩을 하고자 한다면, 매핑 어노테이션에 fetch = FetchType.LAZY 속성을 추가해주면 된다.

지연로딩은 프록시 객체를 이용한다. (간단히. 프록시란, 어떤 다른 객체를 대신하여 특정 동작을 수행하는 객체.)
실제로 사용되기 전까지는 프록시 객체를 넣어두고, 실제로 사용하게 된다면, 데이터베이스에 쿼리를 날리는 것이다.

@Getter
@Setter
@NoArgsConstructor
@Entity
public class Team {    // Team Entity
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team", fetch = FetchType.LAZY)
    private List<Member> members = new ArrayList<>();

    public Team(String name) {
        this.name = name;
    }
}

--------------------------------------------------------------------

@Getter
@Setter
@NoArgsConstructor
@Entity
public class Member {    // Member Entity
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;

    public Member(String name) {
        this.name = name;
    }
}

위와 같이 즉시로딩이 될 수 있도록 fetch = FetchType.LAZY 속성을 달아주었다.

즉시로딩과 같은 상황에서

memberRepository.findAll();

코드를 실행해보겠다.

Hibernate: 
    select
        m1_0.id,
        m1_0.name,
        m1_0.team_id 
    from
        member m1_0

위와 같이 데이터베이스에 Member 정보만 가져오는 쿼리를 날리는 것을 볼 수 있다.
앞서 말했듯이, 지연로딩에는 프록시 객체가 사용된다. 여기서는 team에 프록시 객체를 넣어두는 것이다.

그리고,

mamber.getTeam();

코드를 실행시키면 Team의 정보를 가져오는 쿼리를 날린다.

무조건 지연로딩(LAZY)을 사용하는 것이 유리할까❓

특정 데이터가 거의 모든 순간에 필요하거나, 데이터의 양이 적다면 지연로딩(LAZY)을 사용하는 것보단 즉시로딩(EAGER)을 사용하는 것이 유리할 수 있다.

데이터의 양이 많다면 지연로딩(LAZY)가 유리하다.
그 이유는, 필요한 시점에서만 데이터를 로딩하기에, 모든 데이터를 바로 가지고 오지 않기 때문이고, 사용하지 않는 데이터들은 불러오지 않아도 되기 때문이다.

바로 뒷 글에 대한 내용❓

바로 뒤에 나올 내용은 N+1문제이다.
N+1 문제가 무엇이고, 어떻게 해결하는지에 대해서 알아보겠다.

profile
Better than yesterday.

0개의 댓글