개발자꿈나무
지연 로딩과 즉시 로딩 본문
★ 지연 로딩
- 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은 기본이 즉시 로딩 -> 지연 로딩으로 설정해줘야 함
'자바 > JPA' 카테고리의 다른 글
값 타입 - 기본 값 (0) | 2023.08.23 |
---|---|
영속성 전이, 고아 객체 (0) | 2023.08.22 |
프록시 (0) | 2023.08.22 |
실전 예제 - 상속관계 매핑 (0) | 2023.08.21 |
복합 키 매핑 (0) | 2023.08.20 |