개발자꿈나무

지연 로딩과 즉시 로딩 본문

자바/JPA

지연 로딩과 즉시 로딩

망재이 2023. 8. 22. 18:07

★ 지연 로딩

- Member 엔티티를 호출할 때 Team 엔티티는 호출하고 싶지 않다면 어떻게 설정해줘야 할까?

@ManyToOne(fetch = FetchType.LAZY) //default : EAGER
@JoinColumn(name = "TEAM_ID", nullable = false)
private Team team;

- @ManyToOne 어노테이션 뒤에 fetch 타입을 LAZY로 지정해주면 된다.

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

Member member = new Member();
member.setName("test1");
member.setTeam(team);
em.persist(member);

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

Member findMember = em.find(Member.class, member.getId());
System.out.println("findMember.class : " + findMember.getTeam().getClass()); //프록시

System.out.println("findMember.teamName : " + findMember.getTeam().getName()); //프록시 초기화 - getTeam()일 때는 아님

- 결과를 확인해보면 em.find를 한 시점에서는 Member 테이블에서만 결과를 조회해오고 이후에 getName()을 통해서 실제 값을 조회해야할 때 select 쿼리를 보내서 Team 에 대한 정보를 가져온 것을 알 수 있다. 그렇기에 findMember.getTeam().getClass()의 결과도 프록시 객체인 것을 확인할 수 있다. (당연히 Member.getClass()는 실제 엔티티인 Member이다.)

 

 

★ 즉시 로딩

@ManyToOne(fetch = FetchType.EAGER) //default : EAGER
@JoinColumn(name = "TEAM_ID", nullable = false)
private Team team;

- FetchType을 EAGER로만 바꿔주면 즉시 로딩이 설정되고, 같은 로직을 실행시키면 한번에 조인을 이용해서 Member와 Team에 대한 정보를 가져온다. 물론 Team 엔티티도 실제 엔티티 객체가 반환된다.

 

 

★ 프록시와 즉시 로딩 주의

  • 실무에서는 가급적 지연 로딩만 사용하는 것이 좋다!!!!!!
    -> 즉시 로딩을 사용하게 되면 예상치 못한 SQL이 발생할 가능성이 높고, JPQL에서 N+1의 문제를 일으킨다.
더보기

* JPQL의 N + 1의 간단한 예시

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

JPQL을 실행시켜보면 select 쿼리문이 총 2번 들어가게 된다.

-> 즉시 로딩은 가져왔을 때 무조건 모든 값이 다 들어있어야 함! JPQL은 먼저 sql로 번역이 돼서 Member 테이블에 대한 정보를 가지고 온 이후에 확인해보니 Team도 가져와야해서 Team을 조회하는 쿼리문이 한번 더 나가게 된 것이다.

만약 member1, member2가 있고 각각 team1, team2에 속해있다고 하면 쿼리문이 총 3번 나가게 될 것이다.

  • @ManyToOne, @OneToOne은 기본이 즉시 로딩 -> 지연 로딩으로 설정해줘야 함
728x90

'자바 > JPA' 카테고리의 다른 글

값 타입 - 기본 값  (0) 2023.08.23
영속성 전이, 고아 객체  (0) 2023.08.22
프록시  (0) 2023.08.22
실전 예제 - 상속관계 매핑  (0) 2023.08.21
복합 키 매핑  (0) 2023.08.20