Spring

[Spring] 지연로딩 vs 즉시로딩

윤진노 2024. 7. 22. 17:16

 

 

 

내가 이전에 페치 조인에 대해 포스팅 한 적이 있다.

페치 조인을 사용하는 이유는 지연로딩 환경에서 N+1 문제를 없애기 위해서라고 말했다.

이번에 공부를하면서 지연로딩과 즉시로딩이 뭔지 다시 한번 확실히 깨닫게 되었지만, 인간은 망각의 동물. 잊지 않기 위해 기록하자.

(면접에 나올 수도)

 

 

 

<이전 발행 글>

2024.07.15 - [Spring] - [Spring] 컬렉션 fetch join(페치 조인) 을 이용한 성능 최적화 및 페이징

 

2024.07.14 - [Spring] - [Spring] JPA 에서 fetch join(페치 조인)이란

 

 

 

 


지연로딩이란?

이전에 프로젝트를 하다가 지연로딩을 사용하다가 일정 부분이 되지 않자 즉시로딩으로 바꿨던 기억이 난다.(페치 조인을 모르던 당시) 지연로딩이 뭔지 다시 한번 알아보자.

 

 

JPA에서 엔티티를 조회할때 데이터를 가져오는 방법으로 지연로딩, 즉시로딩 두가지 방법이 있다.

밑 엔티티 코드를 보자.

 

 

Member 클래스

 

 

기본적인 회원을 나타내는 Member 엔티티 코드이다.

여기서 Team 클래스와 다대일 연관관계를 가지고 있다. 그리고 @ManyToOne 어노테이션 옆에 FetchType.LAZY를 설정해주며 지연로딩을 해주고 있다.

 

여기서 FetchType이란 하이버네이트에서 엔티티를 조회할때 데이터를 어떻게 가져올지를 설정해주는 값이다.

디폴트값으론 FetchType.Eager (즉시로딩)을 채택하고 있다. 그래서, 우리가 지연로딩을 사용하고 싶을때는 위 코드처럼 설정을 해주어야 하는것이다.

 

다시, 돌아가서 우리가 Member를 조회할때, Team에 대한 데이터도 필요할 경우가 있을 수도 있다.

하지만, 이전 포스팅에서 처럼  Member를 가져올때마다 Team에 대한 정보가 꼭 필요할까? 안필요 할 수도 있다.

그럴때를 대비하여 우리는 지연로딩을 사용할 수 있다.

 

 

 

 

 

 

 

 

우리가 지연로딩으로 member를 조회하면 member를 select하는 쿼리문이 나갈것이다.

그리고 team과 연관관계 매핑이 되어 있는것을 발견하고, team을 select하는 쿼리문 대신! 프록시 객체를 생성하여 넣어 둘 것이다.

이렇게 되면 우리는 쿼리문을 줄이고, 성능을 개선하는 길을 발견했다. 이것이 지연로딩이다.

 

 

 

 

 

 

즉시로딩 보단 지연로딩

 

지연로딩 (FetchType.Lazy)

즉시로딩 (FetchType.Eager)

 

엔티티를 조회할때 연관관계가 걸려 있는 객체들을 모두 가져오면 즉시로딩, 정말 필요로 할때 가져오는 것이 지연로딩이다.

그렇다면, Member 객체가 Team 객체를 매번 필요로 할 수 있다. 그럴 때는 즉시로딩을 사용해야 하는 걸까?

 

물론 정답은 없겠지만, "아니요"가 정답에 가깝겠다.

 

 

즉시로딩을 사용한다면, 꽤 큰 문제점이 있을 수 있다.

1. 예상치 못한 쿼리문이 나갈 수 있다.

2. JPQL에서 N+1문제를 야기할 수 있다.

 

페치조인에 대해서 설명할때 N+1문제에 대해서는 알아보았던 기억이 난다. 쿼리문 시간복잡도가 N이라고 생각하면 된다.

 

 

 

 

 

 

 

@ManyToOne, @OneToOne 기본이 즉시 로딩

 *대일 관계는 기본이 즉시로딩으로 채택되어 있다.

 

따라서, 우리는 모두 다 지연로딩으로 바꿔줘야 한다.

 

 

그래서 언제 즉시로딩을 사용해야하는건가요???? -> 사용하지 마세요. 필요할때 가져오고, N+1문제 때는 페치 조인을 사용해서 가져와주세요.