[JPA]즉시로딩과 지연로딩은 언제 사용할까? (feat. 프록시)

2022. 12. 27. 13:51·📂 Backend Engineering
728x90
반응형

즉시로딩과 지연로딩에 대해 정리해 보았다.

즉시로딩과 지연로딩을 어떤 상황에서 사용하는지,

왜 사용하는지에 대한 정리 글이다.

 

먼저 즉시로딩과 지연로딩을 알기 위해선 JPA의 프록시에 대한 개념을 알아야 한다.

여기서는 즉시로딩과 지연로딩에 대한 글이므로 프록시는 아래 글을 통해 간단하게 알아보고 

즉시로딩과 지연로딩을 이해하도록 하자.

 

 

목차
1.프록시란
2.지연로딩
3.즉시로딩

 

 

1. 프록시란?


프록시 정의

대리, 가짜라는 의미를 가지고 있는 proxy.

 

 

프록시 사용이유

ex) Member 엔티티를 조회할 때 Team도 함께 조회해야 할까?

  • 비즈니스 로직에서 필요하지 않을 때를 구분해야 한다. 
  • ⭐️ 낭비가 발생하게 된다.
  • JPA는 이 낭비를 하지 않기 위해, 지연로딩과 프록시라는 개념으로 해결한다.

 

 

프록시 기초

  • JPA에서 em.find() 말고, em.getReference()라는 메서드도 제공된다.
  • em.find() 는 DB를 통해서 실제 엔티티 객체를 조회하는 메서드이고
  • em.getReference()는가짜(프록시) 엔티티 객체를 조회하는 메서드이다.

 

 

2. 지연로딩


지연로딩은 아래와 같이 @OOOToOne으로 끝나는 어노테이션에 fetch = FetchType.LAZY를 선언해준다.

@ManyToOne(fetch = FetchType.LAZY)

 

⭐️ 지연로딩 적용 시 DB가 아닌 프록시에서 가져온다!

프록시는 가짜 객체라고 했다. 낭비를 줄이기 위해 실제 DB가 아닌 

엔티티 모양을 한 프록시라는 가짜 객체에서 엔티티 정보를 가져온다.

 

 

 

Member와 Team 클래스 예제

지연로딩 미적용 시

@Entity(name = "Member")
@Getter
public class Member extends BaseTimeEntity{

@ManyToOne
@JoinColumn(name = "team_id")
	private Team team;
    
}

 

 

지연로딩 적용 시

@Entity(name = "Member")
@Getter
public class Member extends BaseTimeEntity{

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

 

결론

지연로딩을 사용하게 되면 Member와 Team이 각각 분리되어 

Member는 DB를 조회하고, Team은 프록시를 조회한다고 이해했다.

 

쿼리 또한 Member 조회 쿼리 한 번, Team 조회 쿼리 한 번 분리되어 나간다.

즉 성능이 더 뛰어나다.

이를 통해서 Member를 조회할 때 Team을 조회할 필요가 없다면

지연로딩을 걸어서 분리하도록 하자.

 

 

 

반대로 만약 내 서비스는 Member를 조회할 때 Team의 정보도 같이 알고 싶다면

즉시로딩을 적용하면 된다.

 

3. 즉시로딩


@ManyToOne(fetch = FetchType.EAGER)

⭐️ 즉시로딩은 실제 DB에서 한 방에 조회

소제목의 글을 보면 즉시로딩의 핵심이 다 담겨 있다.

즉시로딩을 적용한다면 Member와 Team을 실제 DB에서 한 번에 조회해서

하나의 쿼리로 가져온다.

 

 

 

⭐️ 실무 꿀팁(프록시와 즉시로딩 주의 )

 김영한님 말씀 참고하여 작성했습니다.

 

  • 가급적 지연로딩만 사용
  • 즉시로딩을 사용하면 예상치 못한 SQL 문제 발생
  • 즉시로딩은 JPQL에서 n+1 문제를 발생
  • @ManyToOne / @OneToOne은 기본이 즉시로딩 -> LAZY로 변경해야 함
  • @ManyToMany / @ OneToMany는 기본이 지연로딩

 

문제 발생이유(SQL오류가 나는 이유)

내가 예상한 쿼리가 아닌 다른 쿼리가 나갈 수 있다.

 

왜? 

 

fetch = FetchType.EAGER로 묶여있을 경우

Member만 조회를 필요로 했으나, Team 정보도 같이 나오기 때문!!

이문제가 n + 1로 발생할 수 있고, 서비스가 커지면 걷잡을 수 없다.

 

 

결론

즉시로딩의 문제들로 인해 

실제론 즉시로딩을 사용하지 않는다.

 

 

 

 

 

부족한 내용이 있다면 댓글 부탁드립니다 감사합니다.

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'📂 Backend Engineering' 카테고리의 다른 글

[Querydsl] Querydsl과 DTO와 BooleanBuilder를 활용하여 조회하기  (0) 2023.01.25
[Spring] application-oauth.yml를 .gitIgnore에 등록하지않고 보안을 유지하고, 깃허브 액션을 사용해서 빌드 방법  (0) 2023.01.05
[SQL] AES 전화번호 복호화시 [blob] 문제 해결하기  (0) 2022.11.16
콜라츠 추측 함수로 쪼개어 풀어보기  (0) 2022.10.01
[JAVA] Super() 키워드 예제 / Super 부모, 자식  (2) 2022.09.09
'📂 Backend Engineering' 카테고리의 다른 글
  • [Querydsl] Querydsl과 DTO와 BooleanBuilder를 활용하여 조회하기
  • [Spring] application-oauth.yml를 .gitIgnore에 등록하지않고 보안을 유지하고, 깃허브 액션을 사용해서 빌드 방법
  • [SQL] AES 전화번호 복호화시 [blob] 문제 해결하기
  • 콜라츠 추측 함수로 쪼개어 풀어보기
foodev
foodev
이것저것 개발과 이것저것 리뷰 합니다.
    반응형
    250x250
  • foodev
    개발 개맛집
    foodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (104) N
      • ⭐ Featured (4)
      • 📂 Backend Engineering (36)
      • 📂 Troubleshooting & Ops (10)
      • 📂 Infra & System (7) N
      • 📂 Reflections (21)
        • Year-in-Review (5)
        • Work & Career (10)
        • Lessons Learned (6)
      • 📂 Team Journal (10)
      • 📂 Archive (16)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    해피해킹 꿀팁
    서이추
    typedi란
    토이프로젝트개발일지
    해피해킹 키매핑
    Azure 로그 최소 저장 30일
    개발썰
    해피해킹 카라비너
    nestjs pipe
    nestjs pipe body
    typedi 동작원리
    Azure log 비용 줄이기
    di동작원리
    validation failed (numeric string is expected)
    해피해킹 방향키
    db 날린 썰
    di란
    azure ci/cd
    창업패키지후기
    di의존성
    스냅샷과 히스토리
    인프라 로그 저장 비용 감소하는 방법
    QueryDSL
    db 초기화
    스냅샷과히스토리성 차이
    db 날림
    githubaction 라벨 ci/cd
    githubaction 라벨 배포
    해피해킹 커스텀
    JPA
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
foodev
[JPA]즉시로딩과 지연로딩은 언제 사용할까? (feat. 프록시)
상단으로

티스토리툴바