✔ 깃허브 소스코드
✔ Udemy 강의영상
특정 데이터를 조회하기 위해 쿼리 1번으로 N개의 데이터를 가져왔는데, 각 데이터를 순회하면서 연관 관계에 있는 데이터를 얻기 위해 쿼리를 N번 더 수행하는 문제입니다.
주로 연관 관계에 대한 FetchType을 Lazy로 지정했을 때 주로 발생합니다.
이 방법을 사용하게 되면 해당 데이터를 조회할 때마다 연관 관계에 있는 데이터까지 같이 조회가 되므로 성능면에서는 Lazy 보다 떨어지므로 비추천합니다.
@Entity
@NamedQueries(
value = {
@NamedQuery(name = "query_get_all_courses", query = "SELECT C FROM Course C"),
@NamedQuery(name = "query_get_all_courses_join_fetch", query = "SELECT C FROM Course C JOIN FETCH C.students S")
}
)
public class Course {
@ManyToMany(mappedBy = "courses", fetch = FetchType.Eager)
private List<Student> students = new ArrayList<>();
...
}
EntityGraph
를 생성해줍니다.@Test
@Transactional
public void solvingNPlusOneProblemWithEntityGraph() {
EntityGraph<Course> entityGraph = entityManager.createEntityGraph(Course.class);
entityGraph.addSubgraph("students");
List<Course> courses = entityManager
.createNamedQuery("query_get_all_courses", Course.class)
.setHint("javax.persistence.loadgraph", entityGraph)
.getResultList();
courses
.forEach(course -> LOGGER.info(String.format("Course -> {%s} Students -> {%s}", course, course.getStudents())));
}
SELECT C FROM Course C JOIN FETCH C.students S
@Test
@Transactional
public void solvingNPlusOneProblemWithJoinFetch() {
List<Course> courses = entityManager
.createNamedQuery("query_get_all_courses_join_fetch", Course.class)
.getResultList();
courses
.forEach(course -> LOGGER.info(String.format("Course -> {%s} Students -> {%s}", course, course.getStudents())));
}