지연로딩
- Member만 조회하고 싶은데 굳이 Team까지 가져와야하나?? 지연로딩 사용!
- 지연로딩 : Member만 조회해옴!
- LAZY를 사용해서 프록시로 조회
/* Member.java */
@ManyToOne(fetch = FetchType.LAZY) // Member 클래스만 DB에서 조회한다.
@JoinColumn
private Team team;
/* Main.java */
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member1 = new Member();
member1.setUsername("member1");
member1.setTeam(team);
em.persist(member1);
em.flush();
em.clear();
Member m = em.find(Member.class, member1.getId());
System.out.println("m = " + m.getTeam().getClass()); // 프록시네??
System.out.println("====================================");
m.getTeam().getName(); // 프록시 초기화 (쿼리 날림)
System.out.println("=====================================");
즉시로딩
- 만약 Member와 Team을 같이 사용 할 일이 많다면??? → 즉시로딩!
- 즉시 로딩 : Member + Team 같이 조회함 → EAGER 사용함!
- em.find때 부터 Team 데이터 까지 몽땅 가져옴
/* Member.java */
@ManyToOne(fetch = FetchType.EAGER) // Member 클래스만 DB에서 조회한다.
@JoinColumn
private Team team;
프록시와 즉시로딩 주의
⭐ 실무에서는 가급적 지연로딩만 사용
- 즉시 로딩을 적용하면 예상하지 못한 SQL 발생 ( 테이블이 10개가 join 되면 엄청난 쿼리가 발생할수있음..)
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
em.find는 Id를 가지고 알아서 다 select 하기 때문에 Member와 Team을 한문장으로 알아서 찾지만, JPQL은 적혀진 쿼리 가지고 행동하기 때문에 아래와 같은 쿼리로 10명의 Team을 찾으려면 쿼리가 10개 이상 나갈 수 있다.
List<Member> members = em.createQuery("select m from Member m", Member.class).getResultList();
이 경우 쿼리가 아래처럼 두번 나가게 된다(회원이 한명일때 )
SQL : select * from Member
SQL : select * from Team where TEAM_ID = XXX
만약 회원 두명이 서로 다른 팀을 가지고 있다면??
member는 한번에 가져오고, 2명의 member가 각기 다른 팀이기때문에 team 쿼리를 두번 날린다.
이 부분을 LAZY(지연로딩)으로 변경한다면?
member 쿼리만 생성됨 → Team을 사용하지 않기 때문!
해결방안 : join fetch 사용! (뒤에서 자세히 설명)
List<Member> members = em.createQuery("select m from Member m join fetch m.team", Member.class).getResultList();
@ManyToOne, @OneToOne은 기본이 즉시로딩이다 → LAZY(지연로딩)으로 설정해줘야함!
@OneToMany, @ManyToMany는 기본이 지연로딩: 지연로딩 사용!
'JAVA' 카테고리의 다른 글
[JAVA] 임베디드 타입(복합값) (0) | 2022.01.11 |
---|---|
[JAVA] 영속성 전이(CASCADE) + 고아객체 (0) | 2022.01.06 |
[JAVA] 프록시 (0) | 2022.01.04 |
[JAVA] @MappedSuperclass (0) | 2022.01.04 |
[JAVA] JPA 고급 매핑 (상속 관계 매핑) (0) | 2021.12.16 |