오봉이와 함께하는 개발 블로그

스프링 데이터 JPA - @EntityGraph 본문

BE/JPA

스프링 데이터 JPA - @EntityGraph

오봉봉이 2022. 9. 13. 22:13
728x90

@EntityGraph

연관된 엔티티들을 SQL 한번에 조회하는 방법이다.
@EntityGraph에 대하여 정확하게 이해하기 위해서는 패치조인에 대하여 알고 있어야한다.

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
// '일대다'관계에서 '다'가 연관관계 주인이 되어 FK를 가진다.
private Team team;
@Test
public void findMemberLazy() throws Exception {
    // given
    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", 10, 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());
    }
}

@ManyToOne(fetch = FetchType.LAZY)을 통해 LAZY로 적용했기 때문에 member.getUsername()을 했을 때는 Member만 조회하는 쿼리가 나가고, Team을 조회하는 쿼리는 나가지 않고, 프록시 객체가 나가게 된다.
(member.getTeam().getClass()를 통해 조회하면 XXX.Team$HibernateProxy$XXXXX가 출력된다.)
하지만, member.getTeam().getName();을 통해서 Team의 데이터를 조회하게 되면 Team을 조회하는 쿼리도 나가게 된다.

member -> team은 지연로딩 관계이다.
따라서 다음과 같이 team의 데이터를 조회할 때 마다 쿼리가 실행된다. (N+1 문제 발생)

N+1 문제를 해결하기 위해서는 연관된 엔티티를 한번에 조회하는 페치 조인이 필요하다.

JPQL 페치 조인

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

위 코드를 실행해서 조회하면 조회 한 번에 Team에 대한 정보도 모두 조회하기 때문에 N+1 문제를 해결할 수 있다.

EntityGraph

스프링 데이터 JPA는 JPA가 제공하는 엔티티 그래프 기능을 편리하게 사용하게 도와준다.
이 기능을 사용하면 JPQL 없이 페치 조인을 사용할 수 있다. (JPQL + 엔티티 그래프도 가능)

//공통 메서드 오버라이드
@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> findEntityGraphByUsername(String username);

사실상 페치 조인(FETCH JOIN)의 간편 버전으로 LEFT OUTER JOIN을 사용한다.

NamedEntityGraph 사용 방법

NamedQuery를 사용하듯 EntityGraphNamedEntityGraph로 사용할 수 있다.

@NamedEntityGraph(name = "Member.all", attributeNodes = @NamedAttributeNode("team"))
@Entity
public class Member {}
@EntityGraph("Member.all")
@Query("select m from Member m")
List<Member> findMemberEntityGraph();
인프런 김영한 지식공유자님 강의 : 실전! 스프링 데이터 JPA
728x90
Comments