[Spring/Springboot] @EntityGraph

2024. 12. 22. 07:05CS/Spring

 

@EntityGraph

  • @EntityGraph는 JPA에서 Fetch Join과 유사하게 사용되는 기능
    • 엔티티를 조회할 때 연관된 엔티티를 함께 로딩하여 N+1 문제를 해결
    • @EntityGraph는 JPQL 쿼리가 아닌, 메서드에 직접 설정 ⇒ 특정 엔티티와 그 연관 엔티티를 한 번에 조회할 수 있도록
  • @EntityGraph는 Lazy Loading을 사용하는 연관 엔티티를 즉시 로딩(Eager Loading)으로 바꾸어, 원하는 엔티티와 그 연관된 엔티티를 함께 조회할 수 있도록
  • JPA에서는 지연 로딩(Lazy Loading)으로 인해 연관된 엔티티를 사용할 때마다 쿼리가 추가로 발생하는 N+1 문제가 생기는데, @EntityGraph는 이런 문제를 간단하게 해결

@EntityGraph를 사용하는 방법

  • @EntityGraph를 사용하여 Review 엔티티를 조회하면서 Store와 Member를 한 번에 가져오는 방법
public interface ReviewRepository extends JpaRepository<Review, Long> {

    @EntityGraph(attributePaths = {"store", "member"})
    @Query("SELECT r FROM Review r WHERE r.store.name = :storeName")
    List<Review> findReviewByStoreName(@Param("storeName") String storeName);
}
  • @EntityGraph(attributePaths = {"store", "member"}): Review 엔티티를 조회할 때 store와 member 연관 엔티티를 함께 로딩하도록 설정
    • 즉, Review를 조회하는 쿼리를 실행할 때 Store와 Member 엔티티도 한 번에 가져옴
  • JPQL에서 JOIN FETCH 생략: @EntityGraph를 사용하면 JOIN FETCH를 사용하지 않고도 연관된 엔티티를 가져올 수 있음
    • @EntityGraph가 JOIN FETCH와 같은 역할을 수행

@EntityGraph가 생성하는 쿼리

  • @EntityGraph를 적용한 findReviewByStoreName 메서드를 실행하면, JPA는 Review 엔티티와 함께 Store와 Member 엔티티도 한 번에 조회하는 쿼리를 생성
  • 예를 들어, storeName이 "요아정"인 경우 다음과 같은 쿼리가 실행
SELECT
    r.id, r.body, r.score, r.created_at,
    s.id, s.name, s.address, s.score,
    m.id, m.name, m.email, m.point
FROM
    review r
JOIN
    store s ON r.store_id = s.id
JOIN
    member m ON r.member_id = m.id
WHERE
    s.name = '요아정';

 

  • 이 쿼리는 Review 엔티티와 연관된 Store 및 Member 엔티티를 한 번에 가져와서 추가적인 쿼리를 줄여줌
  • 따라서, Review를 조회할 때 Store와 Member 엔티티에 접근하더라도 추가적인 SQL 쿼리가 발생X ⇒ N+1 문제가 발생X

Fetch Join과 @EntityGraph의 차이점

  • 코드의 간결함: @EntityGraph는 메서드 위에 어노테이션으로 설정하기 때문에, JOIN FETCH 구문을 사용할 필요 없이 간단하게 연관된 엔티티를 한 번에 조회 가능
  • JPQL 쿼리 없이 사용 가능: @EntityGraph는 JPQL 쿼리가 없어도 사용 가능 이는 일반적인 findAll() 같은 기본 메서드와 함께 사용할 때 유용
  • 유연성: @EntityGraph는 기본적으로 Lazy로 설정된 연관 엔티티만 Eager로 로딩하므로, 특정 상황에서만 즉시 로딩이 필요할 때 사용 가능