개발놀이터

지연로딩과 즉시로딩 (프록시) 본문

JPA/JPA

지연로딩과 즉시로딩 (프록시)

마늘냄새폴폴 2021. 8. 24. 22:05

*지연 로딩과 즉시 로딩

지연로딩과 즉시로딩을 알기 전에 프록시라는 것을 짚고 넘어가야 한다.

*프록시
프록시의 의미는 앞에서 대신 무언갈 중계해준다. 정도의 느낌이다. 프록시 서버도 마찬가지의 매커니즘이다. 그럼 지연로딩과 즉시로딩에서 프록시는 어떤 역할을 할까? 말 그대로 로딩 즉 데이터를 읽어오는 과정을 중계해준다. 

예를 들어서 Member 엔티티와 Team 엔티티가 있다고 가정해보자, 비지니스 로직상 Member에 있는 데이터들만 조회하거나 입력할텐데 Team까지 필요하진 않을 것이다. 그런데 @ManyToOne 혹은 @OneToOne 어노테이션에서는 em.find(Member.class, member.getId()); 를 하면 Member 테이블은 물론이고 Team까지 조인해서 값을 가져온다. 만약 엮여있는 테이블이 한두개가 아니라 수십개라면 em.find로 Member만 조회하는 순간 엄청난 쿼리를 볼 수 있을 것이다.

그것을 미연에 방지하고자 JPA는 fetchType을 LAZY로 설정하면 Member엔티티를 조회하는 순간 연관관계로 매핑해놓은 나머지 엔티티들을 프록시 객체에 넣어놓는다. 그리고 실제 프록시 객체를 사용하려고 할 때 초기화(DB조회)를 한다. 

실전에서는 모두 LAZY(지연로딩)로 바꿔야 한다. 즉시로딩의 단점이 치명적인데 
1. 즉시 로딩을 적용하면 예상치 못한 SQL이 발생
2. 즉시 로딩은 JPQL에서 N + 1 문제를 일으킨다.
3. @ManyToOne, @OneToOne은 기본 fetchType이 EAGER(즉시로딩) 이기 때문에 LAZY로 설정해야한다.
4. @OneToMany, @ManyToMany는 기본이 LAZY

여기서 N + 1 문제란?
JPQL은 복잡한 쿼리를 대신 날려주는 기능이라고 보면 편한데, SQL문을 대신 날려주기 때문에 적혀있는 SQL문 이외에 일체 다른 행동을 하지 않는다. 만약 Member 엔티티와 Team엔티티가 연관관계 매핑이 되어있고 즉시로딩이 설정되어 있다면 JPQL로 createQuery("select m from Member m", Member.class)이렇게 날리면 JPA입장에선 어 Member 엔티티 가져오라는 거구나? 하고 Member 엔티티를 가져오면 Team이랑 연관관계가 매핑되어있는데 즉시로딩이네? 그럼 그때 다시 Team을 select 쿼리를 날려서 가져온다. 이렇게 즉시로딩으로 연결되어있는 테이블이 한두개가 아니고 N개라면 최초의 쿼리(1)를 내보내면 N개만큼 쿼리가 더 나간다고 해서 N + 1 문제라고 하는 것이다.

'JPA > JPA' 카테고리의 다른 글

JPQL 초급  (0) 2021.08.26
값 타입  (0) 2021.08.26
JPA 상속관계 매핑  (0) 2021.08.23
JPA 연관관계의 주인  (0) 2021.08.23
JPA 기본키 매핑  (0) 2021.08.21