일단 이번에도 역시, 해당 과제를 수행하기에 앞서 필요한 개념을 먼저 정리하고 시작하도록 하겠습니다.
// Comment 테이블에서 특정 todoId에 해당하는 데이터 조회 (1개)
Hibernate: SELECT * FROM comments WHERE todo_id = ?
// User 테이블에서 각 댓글의 user 조회 (N번 반복)
Hibernate: SELECT * FROM users WHERE id = ?
Hibernate: SELECT * FROM users WHERE id = ?
Hibernate: SELECT * FROM users WHERE id = ?
...
참고로, 저는 FETCH JOIN
을 활용하는 방식으로 해결하겠습니다!
(추가로, @EntityGraph도 언급할 예정)
그렇다면, 필요한 개념들은 무엇들이 추가적으로 있을까 ?
→ 연관된 엔티티를 조회할 때 어떻게 동작하는지 이해해야 함
→ 기본적으로 @ManyToOne(fetch = FetchType.LAZY) 설정이 되어 있음
→ Hibernate가 어떻게 SQL을 실행하는지 이해 필요 (SHOW_SQL=true 설정)
application.yml
에서 spring.jpa.properties.hibernate.default_batch_fetch_size=100
설정 가능이제 본격적으로 코드 수정 해보겠습니다.
첫 번째로 CommentRepository를 수정해야합니다. (JPQL FETCH JOIN 적용)
FETCH JOIN 추가함으로써 N+1 문제 해결했습니다.
(JOIN FETCH)로 수정
를 아래와 같이 수정.
스트림 api를 활용하면 좀 더 좋은 코드가 될 것 같아 수정햿으며(참고 1, 2, 3-> 주로 3에서 학습함), 코드에 대해 일부 설명 하자면, List<Comment>
를 List<CommentResponse>
로 변환하였습니다.
순서대로 쉽게 설명해보겠습니다.
기존 코드는 향상 for문입니다. iter를 써서 생성한다음에 작성했습니다.
직관적이고 정말 좋은 코드라고 생각합니다. 그러나, 보통 향상된 for문을 쓰면 stream으로 좀 더 간결하게 가독성 좋은 코드로 리팩토링 할 수 있습니다.
이에 반해 저도 한 번 써봤습니다.
스트림api를 쓰면서 이 전에 사용하던 for문을 한 줄로 변환 했으며,
.map()을 활용해서 commnet객체를 commentResponse로 변환했습니다.
그리고 .collect(Collectors.toList())를 사용하여 List<CommentResponse>
로 변환했습니다.
commentList.stream()
.map(comment -> new CommentResponse(
comment.getId(),
comment.getContents(),
new UserResponse(comment.getUser().getId(), comment.getUser().getEmail())
))
.map()
은 Stream 내 요소를 변환하는 메서드Stream을 List<CommentResponse>
로 변환하는 역할
즉, List<CommentResponse>
가 최종적으로 반환되게 됩니다.
// 기존 for문 방식
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squaredNumbers = new ArrayList<>();
for (Integer num : numbers) {
squaredNumbers.add(num * num);
}
System.out.println(squaredNumbers); // [1, 4, 9, 16, 25]
⬇⬇⬇ Stream API 변환
List<Integer> squaredNumbers = numbers.stream()
.map(num -> num * num)
.collect(Collectors.toList());
System.out.println(squaredNumbers); // [1, 4, 9, 16, 25]
즉, Stream API는 반복문을 간결하게 표현하기 위한 도구일 뿐입니다.
이해가 어렵다면 기존 for문 방식으로 작성해보고 Stream API로 변환해보는 연습을 하면 됩니다.