Post

(JPA)즉시 로딩과 지연 로딩

즉시 로딩과 지연 로딩

지연 로딩 LAZY

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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 객체는 Proxy로 가져오게 된다.
  • 실제 team을 사용하는 시점에 초기화를 통해 실제 Entity를 가져오게 된다.
  • 비즈니스 로직 상 멤버와 팀을 함께 조회하는 경우가 적을 경우 사용하면 좋다.

즉시 로딩 EAGEA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Entity
public class Member {
    
    @Id
    @GeneratedValue
    private Long id;
    
    @Column(name = "USERNAME")
    private String name;
    
    @ManyToOne(fetch = FetchType.EAGEA)
    @JoinColumn(name = "team_id")
    private Team team;
    
    ...
}
  • member와 team을 조인을 통해 함께 조회한다.
  • 비즈니스 로직 상 member와 team을 함께 조회하는 경우가 많을 경우 사용하면 좋다.

프록시와 즉시 로딩 주의

  • 가급적 지연 로딩만 사용하는 것이 좋다.(실무 경험 상)
  • 즉시 로딩을 적용하면 예상하지 못한 SQL이 발생할 때가 있다.
    • 수 많은 조인이 발생 할 수 있다.
  • 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
  • @ManyToOne, @OneToOne은 기본이 즉시 로딩이다. -> LAZY로 변경
  • @OneToMany, @ManyToMany는 기본이 지연 로딩이다.

N+1 해결 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Team teamA = new Team();
team.setName("teamA");
em.persist(teamA);

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

Member memberA = new Member();
memberA.setUsername("memberA");
memberA.setTeam(teamA);
em.persist(memberA);

Member memberB = new Member();
memberB.setUsername("memberB");
memberB.setTeam(teamB);
em.persist(memberB);

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

List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
  • 위 코드에서 즉시 로딩 인 경우 member를 가져올때 team을 가져오는 쿼리가 하나 더 발생하기 때문에 N+1 문제가 발생한다.

  • 해결방법

    1. 지연 로딩으로 변경한 후 fetch join 을 사용

    2. @EntityGraph 어노테이션 사용

    3. batch_fetch_size 설정


REFERENCE


#JPA_즉시로딩 #JPA_지연로딩

This post is licensed under CC BY 4.0 by the author.