Free Lines Arrow
본문 바로가기
DataBase/JPA

[JPA] Lazy 와 Eager

by skahn1215 2021. 8. 19.
728x90
반응형

Lazy 란?

  • 지연로딩이라고 한다.

 

 

언제쓸까?

  • Member 객체안에 Team 객체가 있다고 생각해봅시다.
  • Member 안에 team을 쓰는 경우가 드물다면?
  • 보통은 Member 를 조회하면 안에 있는 Team도 같이 조회가 된다.
    그렇게 되면 불필요한 연산이 추가가 되는 것이다. 
  • Lazy를 사용하면 된다.

 

 

 Lazy 예제

  • FetchType.LAZY 를 써주면 된다.
    - @ManyToOne(fetch = FetchType.LAZY) 

Member class

@Entity
public class Member {

    @Id //PK 설정
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "name", nullable = false, length = 100)
    private String username;

    // 프록시 객체로 조회한다.
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEAM_ID")
    private Team team;

}

 

Main

System.out.println("====================================");
Member member = new Member9("Member");
em.persist(member);

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

member.setTeam(team);
em.flush();
em.clear();
// 프록시로 가져온다.
Member member = em.find(Member.class,member.getId());

// 팀에 대한 쿼리는 나가지 않는다 지연 로딩 때문에
System.out.println("member"+member.getTeam().getClass());

// 여기서 팀에대한 쿼리가 나간다.
// System.out.println("member"+member.getTeam().getName());

System.out.println("====================================");

 

결과

Hibernate: 
    select
        member9x0_.MEMBER_ID as MEMBER_I1_19_0_,
        member9x0_.TEAM_ID as TEAM_ID3_19_0_,
        member9x0_.name as name2_19_0_ 
    from
        Member9 member9x0_ 
    where
        member9x0_.MEMBER_ID=?

 

 

설명

member 를 가져오는 쿼리만 발생 했다.

그 이유는 team에 LAZY 설정을 해주었기 때문이다.

위 예제에서 getTeam.getName() 부분에 주석처리를 제거 하면 Team 을 조회 하는 쿼리가 발생한다.

 

 

 

 

Eager 란?

만약 Team 과 멤버가 항상 같이 쓰인다면?

따로따로 호출해서 쓰는게 아니라 한번에 조회가 가능하다.

 

 

Eager 예제

  • FetchType.EAGER를 써주면 된다.
    - @ManyToOne(fetch = FetchType.EAGER) 
@Entity
public class Member {

    @Id //PK 설정
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "name", nullable = false, length = 100)
    private String username;

    // 프록시 객체로 조회한다.
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEAM_ID")
    private Team team;

}

 

결과

left outer join 으로 한번에 가져왔다.

Hibernate: 
    select
        member9x0_.MEMBER_ID as MEMBER_I1_19_0_,
        member9x0_.TEAM_ID as TEAM_ID3_19_0_,
        member9x0_.name as name2_19_0_,
        team9x1_.TEAM_ID as TEAM_ID1_26_1_,
        team9x1_.name as name2_26_1_ 
    from
        Member9 member9x0_ 
    left outer join
        Team9 team9x1_ 
            on member9x0_.TEAM_ID=team9x1_.TEAM_ID 
    where
        member9x0_.MEMBER_ID=?
member9class lazy.Team9

 

 

 

 

프록시와 즉시로딩 주의점

 

 

즉시로딩 적용시 예상치 못한 SQL 이 발생한다.

  • -join이 너무 많이 나간다.
  • find 할 경우 Eager 10개를 걸면 join이 10개가 나간다.
  • 실무에서 는 지연로딩을 써야 한다.

 

 

즉시로딩은 JPQL에서 N+1 문제를 발생 시킨다.

  • 1 개의 쿼리를 수행 했지만 추가로 N개의 쿼리가 나간다.
  • em.find는 최적화 해서 가져오지만
    jpql은 그대로SQL 로번역이 된다.

  • N+1 이 되는과정
  • Member 만 select 한다. (1)
  • Member 만 select 했지만 Team 이 즉시로딩으로 되어 있으니
  • Team을 또 쿼리로 가져온다.(N+1)

 

 

정리

  • XtoOne 은 기본이 즉시 로딩
  • XtoMany 는 기본이 지연로딩이다.
  • 모든 연관관계에 지연로딩을 쓰자.
  • 실무에서 즉시 로딩을 사용하지 말자.
  • 참고로 JPQL 에서 fetch join을 쓰면 N+1 문제를 해결 할 수 있다.
728x90
반응형

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

[JPA] 값타입  (0) 2021.08.22
[JPA] CASCADE  (0) 2021.08.22
[JPA] 프록시  (0) 2021.08.11
[JPA] @MappedSuperclass  (0) 2021.08.09
[JPA] 고급 매핑1: 상속관계 맵핑  (0) 2021.08.08

댓글