Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

DOing

[JPA] Fetch - 즉시 로딩, 지연 로딩 본문

JPA

[JPA] Fetch - 즉시 로딩, 지연 로딩

mangdo 2021. 7. 14. 22:26

⌚ 지연 로딩(FetchType.LAZY)

@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;
    ..
}

 

- Entity를 처음 생성할때

 

- 실제로 객체를 조회할때

 

Team team = member.getTeam();

team.getName(); // 실제 team을 사용하는 시점에 프록시 초기화 이때 쿼리가 나간다.

 

단순히 getTeam()으로 가져올 때가 아니고 team에 있는 무언가를 실제 사용할때 초기화된다! 

 

⌚ 즉시 로딩(FetchType.EAGER)

@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;
    ..
}

: Member를 로딩할때 Team까지 조인해서 가져온다.

 

⌚ 지연 로딩 VS 즉시 로딩

가급적 지연로딩만 사용해야한다!!! 특히 실무에서와 같이 테이블이 복잡하게 얽혀있는 경우에는 지연로딩을 사용해야한다. 그이유는 다음과 같다.

1. 즉시로딩을 사용하면 예상하지 못한 SQL이 발생한다.

 -> 사실 이 이슈는 내가 진행하던 프로젝트에서 발생했었다. (실제 프로젝트 이슈)

2. 즉시로딩은 JPQL에서 N+1 문제를 일으킨다.

 

  즉시 로딩의 N+1 문제

List<Member> members = em.createQuery("select m  from Member m", Member.class).getResultList();
// JPQL은 그대로 SQL로 번역이된다.
// 즉 Member만 일단 SELECT한다.
// Member 다가져왔는데 EARGER러구...? Team을 다시 가져올게!

// SQL 1 : select * from Member
// SQL N : select * from Team where TEAM_ID = xxx

쿼리를 하나를 날렸는데 N개가 딸려올 수 있다. 실무에서는 JPQL을 많이 사용하고 이러한 문제가 많이 발생한다고 한다.

이 문제를 해결하기 위해서는 모든 연관관계를 일단 지연로딩으로 해야한다.

그러고 정말 필요해서 같이 조인해야한다면, Fetchjoin 이라는 동적으로 원하는 쿼리들을 한번에 가져올 수 있다.

List<Member> members = em.createQuery("select m  from Member m join fetch m.team", Member.class).getResultList();

 

  fetch 기본값

1. @ManyToOne, @OneToOne은 기본이 즉시 로딩-> LAZY로 설정

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