자바생
article thumbnail
Published 2022. 4. 13. 13:24
@EntityGraph Spring 강의/Spring data JPA
728x90

@EntityGraph?

  • 연관관계를 맺은 엔티티들을 SQL 한번에 조회
    • fetch join과 매우 유사하다고 생각

 

연관된 엔티티를 한번에 조회하는 다양한 방법

 

가정

  • Member와 Team은 N:1 양방향 연관관계를 가짐
  • member1은 team1, member2는 team2, member3은 team3, member4는 team4
  • member, team 지연로딩 설정
List<Member> members = memberRepository.findAll();

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

 

지연 로딩으로 인한 N+1 문제

  •  member.teamClass
    • LAZY이기 때문에 실제 엔티티가 아닌 프록시 객체를 가지는 것을 알 수 있다
  • Member를 조회하기 위해 1개의 쿼리를 날렸지만 각 Member의 Team 엔티티를 사용하기 위해서는 연관된 엔티티의 개수(N)만큼 쿼리를 날려야한다
    • 현재 각 Member와 연관된 Team 객체는 총 4개가 있으므로 4개의 select 쿼리가 나가는 것을 알 수 있다
  • 이러한 문제를 "지연로딩을 통한 N+1"이라고 한다

 

JPQL의 fetch join

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

  • Member를 조회할 때, 연관된 엔티티들을 조회하여 가져온다
  • Team class를 보면 앞서 지연로딩과 다르게 proxy 객체가 아닌 실제 엔티티임을 알 수 있다

 

하지만 매번 fetch join을 할 때마다 JPQL을 작성해야한다

"간단한" fetch join을 편하게 사용하기 위해 spring data jpa가 "@EntityGraph"라는 것을 제공한다

 

@EntityGraph 

@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();

 

  • attributePaths를 이용하여 연관된 엔티티를 지정하여 페치 조인할 수 있다

  • fetch join 사용했을 때의 쿼리가 같고, Team 클래스 또한 실제 엔티티라는 것을 알 수 있다

 

@EntityGraph을 다양한 방법으로 사용

 

앞서 배웠던 쿼리 메서드에 @EntityGraph를 사용할 수 있으며, "공통 메서드"를 오버라이딩하여 사용할 수 있다

 

공통 메서드를 오버라이딩하여 사용( CrudRepository 메서드)

@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();

 

JPQL + @EntityGraph

@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"))
public class Member {
	/// 코드
}
@EntityGraph("Member.all")
List<Member> findEntityGraphByUsername(@Param("username") String username);
  • 멤버를 조회할 때마다 "자주" 팀을 같이 사용하기 때문에 사용하는 경우가 많다

 

@EntityGraph랑 fetch join이랑 다른 점이 있을까?

  • join fetch을 명시하여 사용할 경우(별 다른 옵션 지정X) join 전략이 inner join
  • @EntityGraph는 left outer join

앞서 "JPQL의 fetch join" 과 "@EntityGraph"의 쿼리를 참고해보면 알 수 있다

 

JPQL + @EntityGraph 쿼리도 left outer join을 사용할까에 대해 궁금할 수도 있어 올려보겠다

left outer join을 사용한다

 


REFERENCES

스프링 데이터 JPA(김영한 님)

 

728x90

'Spring 강의 > Spring data JPA' 카테고리의 다른 글

벌크 연산  (0) 2022.04.12
페이징과 정렬  (0) 2022.04.11
쿼리 메서드  (0) 2022.04.08
profile

자바생

@자바생

틀린 부분이 있다면 댓글 부탁드립니다~😀

검색 태그