본문 바로가기
  • Let's study
BackEnd/Spring

[Spring] Lazy Loading vs Eager Loading

by 코딩고수이고파 2026. 8. 5.

JPA에서 연관된 엔티티를 언제 조회할 것인지를 결정하는 옵션이다.

 

  • LAZY : 실제로 사용할 때 조회
  • EAGER : 부모를 조회할 때 함께 조회
구분 LAZY (지연 로딩) EAGER (즉시 로딩)
조회 시점 사용할 때 조회 부모 조회 시 함께 조회
SQL 실행 필요할 때 추가 SELECT JOIN 또는 추가 SELECT 즉시 실행
성능 일반적으로 더 좋음 불필요한 데이터까지 조회 가능
기본값 대부분의 컬렉션(@OneToMany) 대부분의 단일 참조(@ManyToOne)
추천 대부분의 경우 추천 반드시 항상 필요한 경우만 사용

EAGER

public class Question {
    @OneToMany(
        mappedBy = "question",
        fetch = FetchType.EAGER
    )
    private List<Answer> answers = new ArrayList<>();
}

 

Question 하나를 조회하면 Answer도 함께 조회한다.

 

Question question = questionRepository.findById(1).get();

 

실제로 Answer를 사용하지 않아도 이미 조회되어 있다.

 

Question 조회
        ↓
Answer도 함께 조회

 

항상 같이 가져오기 때문에 사용하지 않는 데이터까지 조회될 수 있어 성능상 불리하다.

LAZY

@OneToMany(
    mappedBy = "question",
    fetch = FetchType.LAZY
)
private List<Answer> answers = new ArrayList<>();

 

Question만 먼저 조회한다.

 

Question question = questionRepository.findById(1).get();

 

이 시점에는 Answer를 조회하지 않는다. 답변을 실제로 사용할 때

 

question.getAnswers();

 

그 순간 Answer 조회 SQL이 실행된다.

 

Question 조회
        ↓
Answer는 아직 조회 X
        ↓
getAnswers()
        ↓
Answer 조회

 

필요한 경우에만 조회하므로 대부분 성능이 더 좋다.

LAZY에서 자주 발생하는 오류

다음 코드는 LazyInitializationException오류가 발생할 수 있다.

 

Question question = questionRepository.findById(1).get();

question.getAnswers();

 

LAZY는 실제 사용할 때 DB에 접근한다.

하지만 이미 트랜잭션이 종료되어 영속성 컨텍스트가 사라졌기 때문에 조회할 수 없다.

해결 방법

트랜잭션 안에서 조회하도록 한다.

 

@Transactional
public void test() {
    Question question = questionRepository.findById(1).get();

    List<Answer> answers = question.getAnswers();
}

 

트랜잭션이 살아 있으므로 Answer를 정상적으로 조회할 수 있다.

언제 어떤 것을 사용할까?

  • LAZY
    • 대부분의 상황에서 사용
    • 필요한 데이터만 조회하므로 성능이 좋다.
  • EAGER
    • 항상 함께 사용하는 데이터일 때만 사용
    • 사용하지 않는 데이터도 함께 조회될 수 있으므로 남용하지 않는 것이 좋다.

실무에서도 특별한 이유가 없다면 LAZY를 기본으로 사용하는 경우가 많다.

@OneToMany / @ManyToOne

OneToMany는 기본적으로 Lazy가 적용되어 있고, ManyToOne 기본적으로 Eager가 적용되어 있다.

댓글