본문 바로가기
JPA

[JPA] 즉시로딩과 지연로딩

by byeongoo 2020. 4. 22.

1. 즉시로딩과 지연로딩

앞의 포스팅에서 즉시로딩과 지연로딩을 이해하기 위해서 프록시에 대해서 공부를 하였습니다. Member를 조회할 때 연관된 Team도 함께 조회해야할까요?

비즈니스로직에 필요하지 않는데 연관관계가 걸려있다고해서 Team을 가지고오면 손해입니다. 그래서 jpa는 지연로딩이라는 옵션을 제공합니다.

Team team = new Team();
team.setName("teamA");
em.persist(team);

Member member1 = new Member();
member1.setUsername("member1");
member1.setTeam(team);

em.persist(member1);

em.flush();
em.clear();

Member m = em.find(Member.class, member1.getId());

System.out.println("m = " + m.getTeam().getClass());

결과를 보면 m = class hellojpa.Team$HibernateProxy$yChKvCrZ 이런식으로 프록시가 나오는걸 볼 수 있습니다. 뒤에 이 코드를 추가하면 프록시 객체가 초기화되면서 DB에서 값을 가지고옵니다. 지연로딩으로 세팅하면 연관된걸 프록시로 가지고옵니다.

System.out.println("================");
m.getTeam().getName();
System.out.println("================");

지연로딩으로 세팅하면 연관된걸 프록시로 가지고옵니다. FectType을 LAZY로 세팅하면 프록시로 가지고옵니다. 이거를 지연로딩이라고합니다.

@Entity  
public class Member {
    @Id    
    @GeneratedValue    
    private Long id;

    @Column(name = "USERNAME")    
    private String name;

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

지연로딩을 사용시 team을 실제로 사용하는 시점에 초기화됩니다.

그런데 비즈니스로직 대부분이 Member와 Team을 대부분 같이 사용하면 지연로딩처럼 2번 조회하면 성능상 손해를 봅니다.

 

즉시 로딩 EAGER를 사용하면 member와 team을 조인을해서 한방에 가지고 옵니다. 이때 클래스 타입은 실제 entity입니다. 

@Entity  
public class Member {

    @Id    
    @GeneratedValue    
    private Long id;

    @Column(name = "USERNAME")    
    private String name;

    @ManyToOne(fetch = FetchType.EAGER) //**   
    @JoinColumn(name = "TEAM_ID")    private Team team;
}    

대부분의 JPA 구현체는 가능하면 조인을 통해 한번에 가지고 오려고합니다. 하지만 실무에서는 가급적 지연 로딩만 사용합니다. 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생합니다. 조인이 수십개가 걸리면 다른 차원의 문제가 됩니다.

 

[프록시와 즉시로딩 주의]

  • 가급적 지연 로딩만 사용(특히 실무에서)
  • 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생
  • 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
  • @ManyToOne, @OneToOne은 기본이 즉시 로딩
 -> LAZY로 설정
  • @OneToMany, @ManyToMany는 기본이 지연 로딩
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();

즉시로딩은 JPQL에서 N+1 문제를 일으킵니다. 쿼리가 2번 나가는걸 확인할 수 있는데, JPQL을 먼저 SQL로 번역을 합니다. 그러면 Member만 셀렉트를하고, team이 즉시로딩으로 되있기 때문에 team을 가져오기 위해 쿼리가 또 나갑니다.

 

결론을 말씀드리면 모든 연관관계에서 지연로딩을 사용해야합니다. 실무에서는 즉시로딩을 사용하면 안됩니다.

REFERENCE

https://www.inflearn.com/course/ORM-JPA-Basic

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 서버 데이터베이스 프레임워크 및 라이브러리 프로그래밍 언어 서비스 개발 Java JPA Spring Data JPA 온라인 강의 ORM, JPA, 자바, java, 우아한형제들

www.inflearn.com

 

'JPA' 카테고리의 다른 글

[JPA] 고아객체  (0) 2020.04.22
[JPA] 영속성전이(CASCADE)와 고아 객체  (0) 2020.04.22
[JPA] 프록시  (0) 2020.04.22
[JPA] @MappedSuperclass 애노테이션  (0) 2020.04.19
[JPA] 상속 관계 매핑(고급매핑)  (0) 2020.04.19