Spring

JPA @EntityGraph(attributePaths = "authorities")

MDanderson 2023. 6. 13. 05:26

Spring Data JPA의 @EntityGraph 어노테이션은 엔티티 조회 시 해당 엔티티의 특정 관계를 함께 조회할 수 있도록 하는 기능입니다. 이를 Eager Fetching이라고도 합니다.

이 어노테이션을 사용하면, 한 엔티티를 조회하는 동안 다른 관련된 엔티티도 함께 조회하여 효율적으로 데이터를 로딩할 수 있습니다. 이는 N+1 문제를 해결하는 데 도움이 됩니다.

위에서 @EntityGraph(attributePaths = "authorities")를 사용하여 User 엔티티를 조회할 때 authorities와 연관된 엔티티도 함께 조회하도록 설정하였습니다. 즉, findOneWithAuthoritiesByUsername(String username) 메서드를 호출하면, 해당 사용자와 해당 사용자의 모든 권한(authorities)이 함께 조회됩니다. 이렇게 하면 한 번의 조회로 필요한 모든 데이터를 얻을 수 있으므로 성능 향상을 기대할 수 있습니다.

 

 

 

@Query 어노테이션을 사용하여 findOneWithAuthoritiesByUsername(String username) 메서드를 나타낼 수 있습니다.

@Query 어노테이션을 사용하면 JPQL(Java Persistence Query Language) 또는 Native SQL을 사용하여 메서드에 직접 쿼리를 명시할 수 있습니다. 아래는 JPQL을 사용한 예시입니다.

 

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u LEFT JOIN FETCH u.authorities WHERE u.username = :username")
    Optional<User> findOneWithAuthoritiesByUsername(@Param("username") String username);
}

위의 JPQL 쿼리에서 LEFT JOIN FETCH 구문은 User 엔티티와 그에 연관된 Authority 엔티티를 한 번의 쿼리로 함께 조회하기 위해 사용되었습니다. 이렇게 하면 User 엔티티를 조회한 후에 추가로 Authority 엔티티를 조회하는 별도의 쿼리가 발생하지 않으므로 성능 향상을 기대할 수 있습니다.

단, @Query를 사용하여 직접 쿼리를 명시하는 경우, 해당 쿼리가 JPA 및 데이터베이스 스키마와 정확히 일치해야 한다는 점을 주의해야 합니다. 또한, 복잡한 쿼리를 작성해야 할 경우 JPQL보다는 Native SQL을 사용하는 것이 더 편리할 수 있습니다.

 

@EntityGraph 어노테이션은 Spring Data JPA에서 엔티티의 관계를 한 번에 로딩하는 방법을 제어할 수 있는 방법 중 하나입니다. 이 어노테이션을 사용하면 Lazy Loading이나 Eager Loading과 같은 로딩 전략을 세부적으로 조절할 수 있습니다.

이름 기반의 쿼리 메서드(findOneWithAuthoritiesByUsername와 같은 것)는 JPA에 의해 자동으로 해석되지만, 메서드 이름에 authorities가 포함되어 있다고 해서 authorities와 연관된 엔티티가 로딩되는 것은 아닙니다. 메서드 이름은 오직 쿼리의 WHERE 조건절을 구성하는데만 사용됩니다.

따라서 @EntityGraph(attributePaths = "authorities")가 없다면 User 엔티티가 로딩될 때 authorities와 연관된 엔티티는 로딩되지 않을 것입니다. 대신, 이들 엔티티는 처음으로 접근되었을 때(즉, 필요할 때) 로딩됩니다. 이는 Lazy Loading 전략에 따릅니다.

만약 @EntityGraph(attributePaths = "authorities")를 사용한다면, User 엔티티가 로딩될 때 authorities와 연관된 엔티티도 함께 로딩됩니다. 이는 Eager Loading 전략에 따릅니다.

그러므로 이 어노테이션의 사용 여부는 애플리케이션의 성능과 동작 방식에 큰 영향을 미칠 수 있습니다. 만약 해당 관계의 엔티티가 항상 필요한 경우라면 Eager Loading을 사용하여 처음부터 로딩하는 것이 효율적일 수 있습니다. 반면, 해당 관계의 엔티티가 항상 필요하지 않은 경우라면 Lazy Loading을 사용하여 필요할 때만 로딩하는 것이 효율적일 수 있습니다.

 

메서드 이름에서 "WithAuthorities"를 뺀다고 해서 @EntityGraph(attributePaths = "authorities") 어노테이션이 작동하지 않는 것은 아닙니다. Spring Data JPA는 @EntityGraph 어노테이션을 보고 해당 엔티티를 Eager Loading 방식으로 로딩하게 됩니다.

따라서 메서드 이름을 findOneByUsername(String username)처럼 바꾸더라도 authorities와 연관된 엔티티는 여전히 로딩될 것입니다.

그러나 메서드 이름에서 "WithAuthorities"를 제거하면 해당 메서드가 authorities를 로딩하는지 코드를 읽는 사람에게 바로 알려주지 않게 됩니다. 그래서 이 메서드가 authorities를 로딩한다는 것을 명시적으로 알려주기 위해 메서드 이름에 "WithAuthorities"를 포함하는 것이 좋습니다. 이것은 코드의 가독성과 유지 관리성을 높이는 데 도움이 됩니다.