[자바 ORM 표준 JPA 프로그래밍 - 기본편] 8-2강
https://inf.run/2zDo 강의를 수강하고 작성하는 게시물입니다.
1. 지연로딩(LAZY)을 사용해서 조회
@Entity
Public Class Member{
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn
  Team team;
}
위와같이 fetch에 LAZY 속성으로 코딩하고 객체를 조회하면 Member클래스만 DB에서 조회하고 Team 객체는 조회하지 않는다.
Team 객체는 프록시로 세팅되게 된다.
Team에서 실제 값을 사용하면 그 때 객체를 초기화한다.
2. 즉시로딩(EAGER)을 사용해서 조회
@Entity
Public Class Member{
  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn
  Team team;
}
위와 같이 fetch에 EAGER 속성으로 코딩하고 객체를 조회하면 Member 클래스를 조회할때 join해서 Team까지 가져온다.
3. 실무에서는 즉시로딩을 쓰면 안된다.
가급적 지연로딩만 사용해야한다.
- 즉시 로딩을 사용하면 예상하지 못한 SQL이 나간다.
- 즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.
N+1 문제 예제
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();
        EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        try {
            Team teamA = new Team();
            teamA.setName("TeamA");
            em.persist(teamA);
            Team teamB = new Team();
            teamB.setName("TeamB");
            em.persist(teamB);
            Member member1 = new Member();
            member1.setName("member1");
            member1.setTeam(teamA);
            em.persist(member1);
            Member member2 = new Member();
            member2.setName("member2");
            member2.setTeam(teamB);
            em.persist(member2);
            em.flush();
            em.clear();
            
            Member m = em.find(Member.class, member.getId());
            List<Member> members = em.createQuery("select m from Member m",
                Member.class).getResultList();
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
            System.out.println("e = "+e);
        } finally {
            em.close();
        }
        emf.close();
    }
만약 find 부분을 주석처리하고 createQuery만 사용한다고 해도 sql문이 두번나간다.
처음에 sql문을 그대로 전송한다. 그러면 member 테이블의 데이터만 쭉 다 가져온다. 그 후 객체를 생성하려고 보니 Team이 EAGER 속성이므로 team을 쭉 가져오게된다.
select * from Member
select * from Team where TEAM_ID == MEMBER_ID
즉 첫 Member 조회 쿼리가 1번 나가고 Member의 데이터 수 만큼 쿼리가 N번 추가적으로 나간다.
쿼리가 N+1 번 나간다고해서 N+1 문제이다.
부하를 줄이기 위해 속성을 LAZY로 하면 Member조회 쿼리만 한번 나간다.
그래서 해결책은 모든 연관관계는 LAZY로 부여한다. 그 후 3가지 방법이 있다.
- 패치조인
- 엔티티그래프어노테이션
- 배치사이즈
주로 패치조인을 사용한다.
3.1. fetch join
동적으로 내가 원하는 것을 선택해서 한번에 싹 가져오는 것이다.
앱에서 어떤 화면에서는 member만 필요하고 어떤 화면에서는 team만 필요할텐데
만약 두개 다 필요하면 join쿼리를 이용해서 가져오는 것이다.
나중에 수업시간에 나오겠지만 예시를 들어보면 아래와 같다.
List<Member> members = em.createQuery("select m from Member m join fetch m.team",
                Member.class).getResultList();
모든 데이터가 채워져서 나온다.
XToOne 에서의 기본설정
기본이 즉시로딩으로 되어있다. 그러므로 LAZY를 직접 입력해서 설정해야한다.
댓글 남기기