
EntityGraph
지연로딩 간단 개념
엔티티를 설계할 때 연관관계 매핑에서 FetchType을 보통 LAZY로 설정해주는 게 일반적이다.
지연로딩이라고 흔히 부르는 이 설정은 다양한 연관관계로 매핑되어 있는 엔티티를 호출할 때
셀렉트 쿼리의 최적화를 위해 다른 엔티티를 프록시 객체로 생성하는 것을 말한다.
ex) Member와 Team이 N:1(다대일) 관계일 때 Member 엔티티를 호출하면 Team 엔티티는 프록시 객체로 생성되고 Member에만 select 쿼리를 날린다.
쿼리 최적화를 위해 지연로딩 설정을 해주지만 오히려 이런 설정이 최적화에 불리할 때가 있다.
Member(N) : Team(1) 엔티티 관계를 예로 들겠다.
Member를 생성하면 Team은 프록시 객체다.
그렇기에 Team 엔티티가 필요해지면, Team을 위한 별도의 select 쿼리가 추가로 실행된다.
각각 다른 Member 10개와 그 안에 매핑된 각각의 Team이 1개씩 총 10개가 필요하다면, 쿼리 실행 횟수는 최소 20(Member 개수 + Team 개수)이 될 것이다.
그 외의 엔티티가 더 복잡하게 엮여있다면 그 회수는 기하급수적으로 증가할 수 있다.
그런데 애초에 Member 엔티티에 select 쿼리를 보낼 때 Team 까지 한번에 조회한다면 쿼리 실행 횟수는 Member의 개수인 N번으로 줄어든다.
그것을 도와주는게 EntityGraph다.
EntityGraph는 엔티티를 조회할 때 페치 조인(Fetch Join)으로 한번에 모든 엔티티를 가져오게 도와준다.
EntityGraph 사용 방법
@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
레파지토리에 구현된 메서드 중 원하는 것에 @EntityGraph 어노테이션을 추가한다.
그리고 attributePaths로 Member와 매핑된 Team 객체의 변수 명을 입력해준다.
현재 예시에서 Member 엔티티는 아래 처럼 구현된 상태이니 참고하면 된다.
@Entity
@Getter
@Setter
public class Member {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "team_id")
private Team team;
이렇게 하고 위에서 구현한 메서드를 호출하면 Member와 Team 객체를 한꺼번에 select 쿼리로 가져오게 된다.
본래 LAZY 설정에 따라 Member 객체에만 select 쿼리를 실행해야 하지만 EntityGraph 설정 덕에 가능한 것이다.
@NamedEntityGraph
약간 다른 방식으로도 가능하다.
@Entity
@Getter
@Setter
@NamedEntityGraph(name = "Member.all", attributeNodes = @NamedAttributeNode("team"))
public class Member {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "team_id")
private Team team;
엔티티에 @NamedEntityGraph 어노테이션을 추가하고 name과 attributeNodes를 작성한다.
attributeNodes는 처음 방법에서 레파지토리에 작성한 attributePaths 대신 넣는다고 보면 된다.
@EntityGraph("Member.all")
List<Member> findAll();
그리고 레파지토리로 와서 구현한 메서드에 @EntityGraph를 붙이고 바로 위에서 작성한 name을 넣으면 된다.
@EntityGraph 없이 해결
EntityGraph는 과정을 편하게 만들어주는 것이며, 순수 JPQL을 작성해 해결할 수도 있다.
@Query("select m from Member m join fetch m.team")
List<Member> findMemberFetchJoin();
페치 조인(Fetch Join)을 사용하면 left join을 통해 Team 엔티티의 값도 가져오게 된다.
EntityGraph를 사용해 예를 든 방법과 결과물은 같다.
복잡한 쿼리가 아니라면 순수 JPQL로 작성하는 것도 고려해볼만 한다.
'스프링 > JPA' 카테고리의 다른 글
[JPA] Cascade(영속성 전이)에 관해 (0) | 2022.11.27 |
---|---|
[JPA] dataSourceScriptDatabaseInitializer 빈 생성 오류 (0) | 2022.11.15 |
[Spring Data JPA] 사용자 정의 레파지토리 생성 (0) | 2022.09.26 |
[Spring Data JPA] Update 쿼리 사용해서 Bulk로 수정하기. (2) | 2022.09.21 |
[Spring Data JPA] 페이징 메서드 구현 - Page 타입 (2) | 2022.09.20 |