SpringDataJPA - @EntityGraph

박민수·2023년 11월 14일
0

JPA

목록 보기
19/24
post-thumbnail

@EntityGraph

EntityGraph가 무엇인지 알아보려면 먼저 JPA의 fetch join지연로딩 개념에 대해서 명확하게 이해를 하고있어야 한다. 먼저 지연로딩 및 fetch join에 대해서 알아보자.

지연로딩

@Entity
public class Member {
	...
    // @ManyToOne(fetch = FetchType.EAGER)
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;
    ...
}

현재 member와 team은 지연로딩 관계(FetchType.LAZY)로 설정되었다. 따라서 member를 조회했을 때 team이 같이 조회되지 않는다. team은 가짜 객체로 조회해 놓고, 실제 team의 데이터를 사용하는 시점에 team을 조회하는 sql이 별도로 실행된다. 반대로 FetchType.EAGER로 설정하면 member를 조회했을 때 team까지 항상 같이 조회한다. (N+1 문제 발생) 아래 테스트 코드를 통해 확인할 수 있다.

@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) {
        member.getTeam().getName();
    }
}

참고: 다음과 같이 지연 로딩 여부를 확인할 수 있다.

//Hibernate 기능으로 확인
Hibernate.isInitialized(member.getTeam())

//JPA 표준 방법으로 확인
PersistenceUnitUtil util = em.getEntityManagerFactory().getPersistenceUnitUtil();
util.isLoaded(member.getTeam());

fetch join (JPQL)

연관된 엔티티를 한번에 조회하려면 fetch join이 필요하다.

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

위 코드를 보면 알수있듯이 fetch join을 사용하려면 JPQL을 무조건 사용해야한다. 그런데 스프링 데이터 JPA는 JPQL을 쓰지 않고 findByName 같은 쿼리 메소드 기능으로 해결하는 경우도 많다. 단순히 쿼리 메소드 기능으로 해결이 되는 상황에 fetch join을 쓰려고 굳이 JPQL을 적는 것은 다소 번거롭다. 스프링 데이터 JPA는 이러한 문제를 해결하기 위해 EntityGraph 기능을 제공한다. EntityGraph 기능을 사용하면 JPQL을 적지 않고 fetch join을 사용할 수 있다. (JPQL + EntityGraph도 가능)

@EntityGraph

Entity Graph는 쉽게 말해서 fetch join의 간편 버전이다. (left outer join 사용)

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

NamedEntityGraph 사용 방법

@NamedEntityGraph(name = "Member.all", attributeNodes = @NamedAttributeNode("team"))
@Entity
public class Member {
}
@EntityGraph("Member.all")
@Query("select m from Member m")
List<Member> findMemberEntityGraph();

참조
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84/dashboard

profile
안녕하세요 백엔드 개발자입니다.

0개의 댓글