JPA의 FetchJoin을 이해해야 @EntityGraph를 이해할 수 있다.

JPA에서 FetchJoin 중요! 

Spring Data JPA에서 @EntityGraph를 사용하여 쉽게 해결할 수 있다.

 

Member 클레스

... 생략
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String username;
    private int age;

    @ManyToOne(fetch = FetchType.LAZY)  // ManyToOne은 fetchType.LAZY (지연로딩)설정 -> 후에 성능 최적화
    @JoinColumn(name = "team_id")
    private Team team;

    ... 생략
}

지연 로딩 : Member를 부르면 Team team; 을 부르지 않고 프록시(가짜 객체)로 채워 넣고 있다가  team의 데이터를 실제로 사용하는 시점에 쿼리가 호출된다.

 

테스트 코드

@Test
    public void findMemberLazy() throws Exception {
        //given
        //member1 -> teamA
        //member2 -> teamB
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        teamRepository.save(teamA);
        teamRepository.save(teamB);
        memberRepository.save(new Member("member1", 10, teamA));
        memberRepository.save(new Member("member2", 20, teamB));
        em.flush();
        em.clear();

        //when
        List<Member> members = memberRepository.findAll();

        //then
        for (Member member : members) {
            System.out.println("member.getUsername() = " + member.getUsername());
            System.out.println("member.getTeam().getClass() = " + member.getTeam().getClass());
            System.out.println("member.getTeam().getName() = " + member.getTeam().getName());
        }
    }

teamName을 부르려는 데 없으니 team 쿼리를 호출한 후 3번처럼 team의 실제 데이터가 출력됨을 확인할 수 있다.

 

조회 수가 많아질수록 추가 쿼리를 계속해서 부르게 되는 문제 발생 : N + 1 문제 라고 함. - 네트워크를 그만큼 왔다갔다 하므로 성능이 좋아질 수가 없다.

 

 

▶ JPA에서는 이걸 fetch 조인으로 해결 함.

@Query에 사용된 JPQL 확인

public interface MemberRepository extends JpaRepository<Member, Long> {

    // fetch join
    @Query("select m from Member m left join fetch m.team")
    List<Member> findMemberFetchJoin();
}

 

테스트 코드 수정

# 호출  repository 메소드 수정

//when
List<Member> members = memberRepository.findMemberFetchJoin();

출력 결과

  • 쿼리

  • 값 - 프록시가 아니라 실제 데이터가 채워진 것을 볼 수 있다.

연관 관계가 있는 것을 데이터베이스의 join을 활용하여 한번에 다 끌고옴.

 

 

▶ 스프링 데이터 JPA  - EntityGraph

@EntityGraph(attributePaths = {"team"})

public interface MemberRepository extends JpaRepository<Member, Long> {
   
    //공통 메서드 오버라이드
    @Override
    @EntityGraph(attributePaths = {"team"})
    List<Member> findAll();
    
    //JPQL + 엔티티 그래프
    @EntityGraph(attributePaths = {"team"})
    @Query("select m from Member m")
    List<Member> findMemberEntityGraph();

    //메서드 이름으로 쿼리에서 특히 편리하다.
    @EntityGraph(attributePaths = {"team"})
    List<Member> findByUsername(String username)
}

 

'프로그래밍 > SpringDataJPA' 카테고리의 다른 글

Auditing (생성일, 수정일, 생성자, 수정자)  (0) 2022.06.19
JPA Hint & Lock  (0) 2022.06.19
벌크성 수정 쿼리  (0) 2022.06.18
스프링 데이터 JPA 페이징과 정렬  (0) 2022.06.18
순수 JPA 페이징과 정렬  (0) 2022.06.18

+ Recent posts