ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • #JPA-14 즉시 로딩과 지연 로딩
    JPA 2021. 2. 19. 17:45

    [출처] 인프런 김영한 강사님 -자바 ORM 표준 JPA 프로그래밍 기본

     

    Member를 조회할 때 Team도 함께 조회해야 할까?

     

    단순히 member 정보만 사용하는 비즈니스 로직 

    println(member.getName());

     

     

    지연 로딩 LAZY을 사용해서 프록시로 조회

    proxy 객체로 조인한다 Member만 DB에서 가져옴.


    지연 로딩

     

    지연 로딩 LAZY을 사용해서 프록시로 조회

     

    Member member = em.find(Member.class,"1L");  //Team은 가짜 proxy

    Team team = member.getTeam(); team.getName();

    실제 team을 실제 사용하는 시점에 초기화(DB 조회)  -> 이때 쿼리가 나간다.

     

     

     

    Member와 Team을 자주 함께 사용한다면? 

    쿼리가 두번씩나감 member 따로 team 따로~~  network가 두번씩 나가는것!

     

     

    즉시 로딩 EAGER를 사용해서 함께 조회

    쿼리가 조회를 할떄 애초부터 맴버 팀 조인해서 한방쿼리로 땡겨옴. 즉시로딩이기때문에 프록시가 필요가없다.

    팀의 class type을 뽑으면 진짜가 나옴.


    즉시 로딩

     

    즉시 로딩(EAGER), Member조회시 항상 Team도 조회

    JPA 구현체는 가능하면 조인을 사용해서 SQL 한번에 함께 조회

     

    프록시와 즉시로딩 주의 

    • 가급적 지연 로딩만 사용(특히 실무에서) 

      

    • 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생

      ->조인이 너무 많이나간다... 조인이 한두개면 얼마안걸리지만 다이걸로 db가 10개가 되있고 이러면 조인 5개가

         무조건 나가 버린다. 걸려있는 테이블을 다 한꺼번에 조회해서 온다.

    Member member1 = new Member();
    member1.setUsername("hello1");
    em.persist(member1);
    
    em.flush();
    em.clear();
    
    
    List<Member> members = em.createQuery("select m from Member m",Member.class).getResultList();
    tx.commit();

    쿼리가 두번나가게 된다.

    em.find라는 것은 딱 pk를 찍어서 가저오는거기 때문에 JPA가 내부적으로 최적화를 할 수 있다.

    하지만

    JPQL같은경우는 JPQL이 SQL로 그대로 번역하고 그결과 위의 JPQL을 보면 member만 SELECT한다.

    만약 MEMBER가 10개라고 쳤을때

    MEMBER  DATA 10개를 쭉가지고 왔더니 TEAM이 즉시로딩(값이 무조건 다 들어가 있어야한다.)으로 되있네? 

    그럼 그다음 TEAM 10개를 또 가져와야한다. 만약 LAZY일 경우에는 proxy로 가지고와도 되지만 EAGER이라서 다시 또 조회해 와야한다.

     

    • 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.(N ->추가 쿼리 , 1-> 최초 쿼리)

    -> 최초 쿼리 1개를 날렷는데, 추가로 N개의 쿼리가 날라가는 문제

    -> LAZY로 잡게될 경우 TEAM이 proxy로 바뀌게 때문에 쿼리가 안날라간다.

    -> 해결방법 : 모든 연관관계를 지연로딩으로 다 깔고, 

             1. fetch join : 동적으로 내가 원하는 애들을 선택해서 한방에 가져오는 것.(경우에따라 쓸 수 있음

                  em.createQuery("select m from Member m join fetch m team",Member.class).getResultList();

                  실행하는 쿼리에 따라서 한방으로 가지고 온다.

                  (기본은 fetch join을 쓴다.)

             2. entity graph

             3. batch size

     

    • @ManyToOne, @OneToOne같은 경우에는 실제로 만들어져있는것을 보면 기본이 즉시 로딩
으로 세팅되어있어서

    자체적으로 -> LAZY로 변경하여 설정해 줘야한다.

     

    • @OneToMany, @ManyToMany는 기본이 지연 로딩

     

     

    지연 로딩 활용

    (지연로딩활용 설명은 극히 이론적인 것 실무에서는 무조건 지연 로딩 )

    • Member와 Team은 자주 함께 사용 -> 즉시 로딩 

    • Member와 Order는 가끔 사용 -> 지연 로딩 

    • Order와 Product는 자주 함께 사용 -> 즉시 로딩

    지연 로딩 활용

    지연 로딩 활용

    proxy인 order을 직접사용하게 되면 product까지 함께 들고오는 것을 사용.(실무에선 무조건 지연로딩)

    지연 로딩 활용 - 실무 

    • 모든 연관관계에 지연 로딩을 사용해라! 

    • 실무에서 즉시 로딩을 사용하지 마라! 

    • JPQL fetch 조인이나, 엔티티 그래프 기능을 사용해라!
 (뒤에서 설명) 

    • 즉시 로딩은 상상하지 못한 쿼리가 나간다.

    'JPA' 카테고리의 다른 글

    #JPA-16 값 타입  (0) 2021.02.22
    #JPA-15 속성 전이: CASCADE  (0) 2021.02.19
    #JPA-13 프록시  (0) 2021.02.19
    #JPA-12 상속관계 매핑  (0) 2021.02.19
    #JPA-11 다양한 연관관계 매핑  (0) 2021.02.18

    댓글

Designed by Tistory.