- ๋๋ถ๋ถ ์๋น์ค๋ CRUD ์ค์ read์ ๋น์ค์ด ํฌ๋ค.
- ๋ํ ์กฐํ API๋ฅผ ๋ง๋ค ๋ ์ ๋ณด์ ์ฒ๋ฆฌ์ ํ์ด์ง์ ์ ์ฉ์ ํญ์ ํจ๊ป ๊ณ ๋ฏผํด์ผ ํ๋ค.
- ๋ชฉ๋ก ์กฐํ API๋ฅผ ๋ง๋ค๊ธฐ ์ํด ํ์ํ ์ ๋ณด๋ ์๋์ ๊ฐ๋ค.
- ๋๋ค์
- ๋ฆฌ๋ทฐ์ ์ ์
- ๋ฆฌ๋ทฐ๊ฐ ์์ฑ๋ ๋ ์ง
- ๋ฆฌ๋ทฐ์ ์์ธ ๋ด์ฉ
- ์ฌ์ง (S3์ ์ฌ์ฉ)
- ์ฌ์ฅ๋์ ๋ต๊ธ (์ฌ์ง๊ณผ ํจ๊ป ์ด๋ฒ API์์๋ ์๋ตํ๋ค)
- API๋ฅผ ๋ง๋๋ ๊ฒ์ ์๋์ ์์๋ฅผ ๋ฐ๋ฅด๋ฉด ํธํ๋ค
- API ์๊ทธ๋์ฒ๋ฅผ ๋ง๋ ๋ค
- API ์๊ทธ๋์ฒ๋ฅผ ๋ฐํ์ผ๋ก API ๋ช ์ธ์์ ๋ช ์ธ๋ฅผ ํด์ค๋ค
- ๋น์ฆ๋์ค ๋ก์ง์ ๋ง๋ ๋ค
- ์ปจํธ๋กค๋ฌ๋ฅผ ์์ฑํ๋ค
- validation ์ฒ๋ฆฌ๋ฅผ ํ๋ค
- ์ด๋ ํ ์์ฒญ์ ์๋ตํ๊ธฐ ์ํ DTO๋ฅผ ๋ง๋๋ ๊ณผ์ ์ด๋ค.
- ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ, ๋ฆฌ์ฟผ์คํธ ๋ฐ๋๊ฐ ํ์ํ ๊ฒฝ์ฐ ํจ๊ป ์ ์ํ๋ค.
์ฌ๋ฌ ๋ฆฌ๋ทฐ DTO๋ฅผ ReviewResDTO๋ผ๋ ํ๋์ ํด๋์ค๋ก ๋ฌถ์ ๋ค ๊ทธ ํ์์์ record๋ static class๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํจ์ผ๋ก์ ์ฝ๋์ ๊ฐ๋ ์ฑ์ ๋์ธ๋ค.
public class ReviewResDTO {
@Builder
public record ReviewPreViewListDTO(
List<ReviewPreViewDTO> reviewList,
Integer listSize,
Integer totalPage,
Long totalElements,
Boolean isFirst,
Boolean isLast
){}
@Builder
public record ReviewPreViewDTO(
String ownerNickname,
Float score,
String body,
LocalDate createdAt
){}
}- ๋ฆฌ๋ทฐ ๋๋ฉ์ธ์ ์ฑ๊ณต/์คํจ ์ฝ๋๋ ๋ฆฌ๋ทฐ โ ์์ธ โ ์ฝ๋ ์๋์ ์์ฑ๋๋ค
@Getter
@RequiredArgsConstructor
public enum ReviewErrorCode implements BaseErrorCode {
NOT_FOUND(HttpStatus.NOT_FOUND,
"REVIEW404_1",
"ํด๋น ๋ฆฌ๋ทฐ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค."),
;
private final HttpStatus status;
private final String code;
private final String message;
}@Getter
@RequiredArgsConstructor
public enum ReviewSuccessCode implements BaseSuccessCode {
FOUND(HttpStatus.OK,
"REVIEW200_1",
"ํด๋นํ๋ ๋ฆฌ๋ทฐ๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์ฐพ์์ต๋๋ค."),
;
private final HttpStatus status;
private final String code;
private final String message;
}- ๋ฆฌ๋ทฐ ๋๋ฉ์ธ์ ์์ธ๋ ๋ฆฌ๋ทฐ โ ์์ธ ์๋์ ์์ฑ
- ์ ์ญ ์์ธ ํด๋์ค๋ฅผ ์์ํ์ฌ ๋ง๋ค์ด์ง๋ค
public class ReviewException extends GeneralException {
public ReviewException(BaseErrorCode code) {
super(code);
}
}// ๊ฐ๊ฒ์ ๋ฆฌ๋ทฐ ๋ชฉ๋ก ์กฐํ
@GetMapping("/reviews")
public ApiResponse<ReviewResDTO.ReviewPreViewListDTO> getReviews(){
ReviewSuccessCode code = ReviewSuccessCode.FOUND;
return ApiResponse.onSuccess(code, null);
}- ์์ง ๋ชจ๋ API๊ฐ ๊ฐ๋ฐ๋์ง ์๋๋ผ๋ ๋ช ์ธ์๋ฅผ ์์ฑํ๋ค.
- ์ด๋ฅผ ํตํด ํ๋ก ํธ์ ๋ณ๋ชฉ์ ์ต์๋ก ํ ์ ์๋ค.
- ๋ง์ฝ API ๋ช ์ธ์๋ฅผ ์ค์จ๊ฑฐ๋ก ๋๋ด๊ณ ์ถ๋ค๋ฉด ๋น ๋ฅธ ๋ฐฐํฌ๊ฐ ํ์ํ๋ค.
- ์ค์จ๊ฑฐ๋ฅผ ์ฌ์ฉํ์ฌ API ๋ช ์ธ ๋ฌธ์๋ฅผ ์๋์ผ๋ก ์์ฑํ๊ณ ์ถ๋ค๋ฉด ์ํ๋ ์ปจํธ๋กค๋ฌ ๋ฉ์๋ ์์ ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์๋ค.
// ๊ฐ๊ฒ์ ๋ฆฌ๋ทฐ ๋ชฉ๋ก ์กฐํ
@Operation(
summary = "๊ฐ๊ฒ์ ๋ฆฌ๋ทฐ ๋ชฉ๋ก ์กฐํ API By ๋งํฌ (๊ฐ๋ฐ ์ค)",
description = "ํน์ ๊ฐ๊ฒ์ ๋ฆฌ๋ทฐ๋ฅผ ๋ชจ๋ ์กฐํํฉ๋๋ค. ํ์ด์ง๋ค์ด์
์ผ๋ก ์ ๊ณตํฉ๋๋ค."
)
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "์ฑ๊ณต"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "์คํจ")
})
@GetMapping("/reviews")
public ApiResponse<ReviewResDTO.ReviewPreViewListDTO> getReviews(){
ReviewSuccessCode code = ReviewSuccessCode.FOUND;
return ApiResponse.onSuccess(code, null);
}@Operation: ํด๋น API ๋ฉ์๋(์๋ํฌ์ธํธ)์ ๋ํ ์์ฝ ์ ๋ณด์ ์์ธ ์ค๋ช ์ ์ ๊ณต@ApiResponse: ํด๋น API ํธ์ถ์ด ๋ฐ์์ํฌ ์ ์๋ ์๋ต ์ฝ๋(์ฑ๊ณต/์คํจ)์ ๋ฉ์์ง๋ฅผ ๋ช ์@ApiResponses: ์์ @ApiResponse๋ฅผ ๋ฌถ์
- ์์ ๊ฒฝ์ฐ ์ค์ ์ปจํธ๋กค๋ฌ์ ๊ตฌํ๊ณผ ๋ช ์ธ์ ์ค์ ์ด ๋ค์์ฌ ์ปจํธ๋กค๋ฌ์ ๋ก์ง์ ์์๋ณด๊ธฐ ํ๋ค์ด์ง๋ค.
- ๋ฐ๋ผ์ ReviewControllerDocs๋ผ๋ ์ธํฐํ์ค์์ ์ค์จ์ด ๊ด๋ จ ์ด๋ ธํ ์ด์ ๋ค์ ์ ์ํ๊ณ ์ด๋ฅผ ์์๋ฐ์ ReviewController๋ฅผ ๋ง๋ค์ด ์ด๊ณณ์์ ๋ก์ง์ ๊ตฌํํ๋ค.
๊ฐ์ฅ ์ฐ์ ์ ์ผ๋ก๋ ๊ตฌํํ๋ ค๋ ๋ฉ์๋์ ํ๋ฆ์ ์๊ฐํ๋ค. ๋ฆฌ๋ทฐ ์กฐํ ๋ก์ง์ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ด ๊ตฌ์ํ ์ ์๋ค.
- ๊ฐ๊ฒ๋ฅผ ๊ฐ์ ธ์จ๋ค โ ๊ฐ๊ฒ๊ฐ ์กด์ฌํ์ง ์๋๋ค๋ฉด ์์ธ๋ฅผ ํฐํธ๋ฆฐ๋ค
- ๊ฐ๊ฒ์ ๋ง๋ ๋ฆฌ๋ทฐ๋ฅผ ๊ฐ์ ธ์จ๋ค โ offset ํ์ด์ง์ ์ฌ์ฉํ๋ค
- ๊ฒฐ๊ณผ๋ฅผ ์๋ต DTO๋ก ๋ฐํํ๋ค โ ์ด๋ DTO์ ์์ฑ์ ์ปจ๋ฒํฐ๋ฅผ ์ด์ฉํ๋ค
- ์กฐํ๋ฅผ ์ํ ๊ฒ์ด๋ฏ๋ก ๋ฆฌ๋ทฐ โ ์๋น์ค โ ์ฟผ๋ฆฌ ์๋์ ์์ฑํ๋ค
- ์ธํฐํ์ด์ค ReviewQueryService๋ฅผ ์์ฑํ๋ค
- ์ ์ธํฐํ์ด์ค๋ฅผ ์์๋ฐ๋ ๊ตฌํ ํด๋์ค ReviewQueryServiceImpl๋ฅผ ์์ฑํ๋ค
- ๋ฆฌ๋ทฐ ์กฐํ๋ฅผ ์ํ ๋ฉ์๋
List<Review> searchReview(String filter, String type) thows Exception;์ ์ ์ํ๋ค.
- ์ปจํธ๋กค๋ฌ๋ ํ๋ก ํธ๋ก๋ถํฐ ๋ฐ์ ์ ๋ณด๋ฅผ ์๋น์ค ๋ฉ์๋๋ก ๋๊ฒจ์ค๋ค.
- ์๋น์ค๋ ์๋น์ค ๋ก์ง์ ์คํ ํ ํด๋น ๊ฒฐ๊ณผ๋ฅผ DTO๋ก ๋ฌถ์ด ๋ฆฌํดํ๋ค.
- ์ปจํธ๋กค๋ฌ๋ ํด๋น ๊ฒฐ๊ณผ๋ฅผ ์ฑ๊ณต ApiResponese๋ก ๊ฐ์ธ ํ๋ก ํธ๋ก ์ ๋ฌํ๋ค.
- ๋ ํฌ์งํ ๋ฆฌ ํด๋์ค๋ฅผ ์ด์ฉํ์ฌ ํ์ํ ์๋น์ค ๋ก์ง์ ์ํํ๋ค.
- ์ด๋ ์ปจํธ๋กค๋ฌ์์ ๊ฐ๊ฒ์ ์ด๋ฆ๊ณผ ํ์ด์ง ์ ๋ณด๋ฅผ ๋ฐ์์จ๋ค.
- ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋
JpaRepository<T,ID>์ธํฐํ์ด์ค๋ListCrudRepository<T,ID>๋ฐListPagingAndSortingRepository<T,ID>๋ฅผ ์์ํ๋ค. - ์ฆ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฆฌ์คํธ ๋ฐํ ๋ฐ ํ์ด์ง/์ ๋ ฌ ๊ธฐ๋ฅ์ ํฌํจํ๋ ๊ฒ์ด๋ค.
ListPagingAndSortingRepository<T,ID>๋ ์ ๋ ฌ ์กฐ๊ฑด(Sort)์ ์ธ์๋ก ๋ฐ์List<T>ํํ๋ก ๋ฐํ๋ฐ๋ ๊ฒ์ด ๊ฐ๋ฅํฉ๋๋ค.- ๋ํ
ListPagingAndSortingRepository<T,ID>์PagingAndSortingRepository<T,ID>๋ฅผ ์์ํ๊ณ ์์ผ๋ฏ๋กPage<T>๋ฅผ ๋ฐํํ๋findAll(Pageable pageable)๋ฑ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค. Page<T>๋Slice<T>๋ฅผ ์์ํ๋ฏ๋ก Slice์์ ์ ๊ณตํ๋ ๋ฉ์๋๋ฅผ ๋ชจ๋ ์ฌ์ฉํ ์ ์๋ค. ์ฌ๊ธฐ์ ์ ์ฒด ์์ ์(getTotalElements()), ์ ์ฒด ํ์ด์ง ์(getTotalPages()) ๋ฑ์ ์ถ๊ฐ ๋ฉ์๋๋ฅผ ์ ๊ณตPageRequest๋ ํ์ด์ง์ด๋ ์ฌ๋ผ์ด์ฑ ์์ฒญ์ ์ํด ํ์ํ ์ ๋ณด(ํ์ด์ง ๋ฒํธ(page), ํ ํ์ด์ง ํฌ๊ธฐ(size), ์ ๋ ฌ ์กฐ๊ฑด(Sort) ๋ฑ)๋ฅผ ๋ด๋Pageable๊ตฌํ ๊ฐ์ฒด์ด๋ค.
ํ์ด์ง ์ธํฐํ์ด์ค๋ ์๋์ ๊ฐ์ด ๊ตฌํ๋๋ค.
public interface Page<T> extends Slice<T> {
// ์ ์ฒด ํ์ด์ง ๊ฐ์
int getTotalPages();
// ์ ์ฒด ์์ ๊ฐ์
long getTotalElements();
// / ๋ณํ๊ธฐ
<U> Page<U> map(Function<? super T, ? extends U> converter); // ๋ณํ๊ธฐ
}ํ์ด์ง์์๋ ์ด ํ์ด์ง ์๊ฐ ์ค์ํ๋ค. Page ํ์ ์ count ์ฟผ๋ฆฌ๋ฅผ ํฌํจํ๋ ํ์ด์ง์ผ๋ก ์นด์ดํธ ์ฟผ๋ฆฌ๊ฐ ์๋์ผ๋ก ์์ฑ๋์ด ํจ๊ป ๋๊ฐ๋ค.
- ํ์ด์ง์์๋ ์ ์ฒด ๋ฐ์ดํฐ์ ๊ฐ์ ์ฆ, count๊ฐ ํ์ํ๋ค.
- ๊ทธ๋ฌ๋ ์ฌ๋ผ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ๋ณ๋๋ก ์นด์ดํธ ์ฟผ๋ฆฌ๊ฐ ์คํ๋์ง ์๋๋ค.
- ๋ฐ๋ผ์ ์ ์ฒด ํ์ด์ง์ ๊ฐ์์ ์ ์ฒด ์ํฐํฐ์ ๊ฐ์๋ฅผ ์ ์ ์์ง๋ง ๋ถํ์ํ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฌ์ง ์์ ์ฑ๋ฅ ๋ญ๋น๊ฐ ๋ฐํํ์ง ์๋๋ค.
- ๋ชจ๋ฐ์ผ UI๋ฑ์์ ์ฌ์ฉ๋๋ ๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํ ๋๋ ์ ์ฒด ํ์ด์ง์ ๊ฐ์๊ฐ ๊ตณ์ด ํ์ํ์ง ์๋ค. ๋ค์ ํ์ด์ง๊ฐ ์กด์ฌํ๋์ง๋ง์ ํ์ธํ๋ฉด ๋๋ค. ์ด๋ด ๋ ์ฌ๋ผ์ด์ค๋ฅผ ์ฌ์ฉํ๋ฉด ์ ํฉํ๋ค.
- ๊ทธ๋ผ ์ฌ๋ผ์ด์ค๋ ์ด๋ป๊ฒ ๋ค์ ํ์ด์ง๊ฐ ์กด์ฌํ๋์ง๋ฅผ ํ๋จํ ๊น?
- ๋ฐํํ์ ์ด ์ฌ๋ผ์ด์ค์ธ ๋ ํฌ์งํ ๋ฆฌ ๋ฉ์๋์ ํ์ด์ง ์ฌ์ด์ฆ๋ฅผ 10์ผ๋ก ์ค์ ํ Pageable ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๋ฉด JPA๋ ๊ฑฐ๊ธฐ์ 1์ ๋ํด 11๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌํ๋ค.
- ์ด๋ฅผ ํตํด ๋ค์ ์ฟผ๋ฆฌ์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ์ ์ ์๋ค.
- ์๋น์ค ํด๋์ค์์ PageRequest๋ฅผ ์์ฑํ๋ค โ ํ์ด์งํ ์ ๋ณด Offset, Limit์ ์ ์
- Repository๋ก ์์ฑํ PageRequest์ ๋๊ฒจ์ค๋ค.
- PA์ PageRequest.of(page, size)์์ page๋ 0๋ถํฐ ์์ํ๋ค.
- ๊ทธ๋ฌ๋ ๋ณดํต ํ๋ก ํธ์๋๋ ํด๋ผ์ด์ธํธ๋ ํ์ด์ง๋ฅผ 1๋ถํฐ ์์ฒญํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
- ์ด๋ฅผ ์ํด ์ปจํธ๋กค๋ฌ์์ page์ -1์ ํด์ค ํ ์๋น์ค๋ก ๋๊ฒจ์ฃผ๋ ๊ฒ์ด ์ข๋ค.
- DB์์ ์กฐํํ ๊ฐ์ฒด๋ฅผ DTO๋ก ๋ณํํ๊ธฐ ์ํ ์ปจ๋ฒํฐ๋ฅผ ์์ฑํ๋ค.
- ์ปจ๋ฒํฐ๋ ๋ ํฌ์งํ ๋ฆฌ์์ ์ ๋ฌ๋ฐ์ Page์ ํ์์ ๋ง์ถฐ DTO๋ก ๋ณํํ๋ค.
- ๋จ ์ด ๊ฒฝ์ฐ review.getMember().getName() ๋ถ๋ถ์์ N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋๋ค โ ์ด๋ ๊ฐ์ฒด ๊ทธ๋ํ ํ์์ผ๋ก ์ด์ด์ง๋ค
public class ReviewConverter {
// result -> DTO
// ์๋์ ReviewPreViewDTO๋ฅผ ์ด์ฉํด Page<Review> ์ ์ฒด๋ฅผ DTO๋ก ๋ณํํ๋ค
public static ReviewResDTO.ReviewPreViewListDTO toReviewPreviewListDTO(
Page<Review> result
){
return ReviewResDTO.ReviewPreViewListDTO.builder()
.reviewList(result.getContent().stream()
.map(ReviewConverter::toReviewPreviewDTO)
.toList()
)
.listSize(result.getSize())
.totalPage(result.getTotalPages())
.totalElements(result.getTotalElements())
.isFirst(result.isFirst())
.isLast(result.isLast())
.build();
}
// ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ์ ReviewPreViewDTO๋ฅผ ์์ฑํ๋ค
public static ReviewResDTO.ReviewPreViewDTO toReviewPreviewDTO(
Review review
){
return ReviewResDTO.ReviewPreViewDTO.builder()
.ownerNickname(review.getMember().getName())
.score(review.getStar())
.body(review.getContent())
.createdAt(LocalDate.from(review.getCreatedAt()))
.build();
}
}@Override
public ReviewResDTO.ReviewPreViewListDTO findReview(
String storeName,
Integer page
){
// ๊ฐ๊ฒ ๊ฐ์ ธ์ค๊ธฐ (์๋ค๋ฉด ์์ธ)
Store store = storeRepository.findByName(storeName)
.orElseThrow(() -> new StoreException(StoreErrorCode.NOT_FOUND));
// ๊ฐ๊ฒ์ ๋ง๋ ๋ฆฌ๋ทฐ ๊ฐ์ ธ์ค๊ธฐ (Offset ํ์ด์ง)
PageRequest pageRequest = PageRequest.of(page, 5);
Page<Review> result = reviewRepository.findAllByStore(store, pageRequest);
// ๊ฒฐ๊ณผ๋ฅผ ์๋ต DTO๋ก ๋ณํ (์ปจ๋ฒํฐ ์ด์ฉ)
return ReviewConverter.toReviewPreviewListDTO(result);
}๊ฐ์ฒด ๊ทธ๋ํ ํ์์ ์ด๋ค ๊ฐ์ฒด๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ทธ ๊ฐ์ฒด์ ์ฐ๊ด๋(์ฐธ์กฐ๋) ๋ค๋ฅธ ๊ฐ์ฒด๋ค์ ์ฐพ์๊ฐ๋ ๊ณผ์ ์ ๋งํ๋ค
๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์์ ๊ฐ์ฒด๋ค์ ์๋ก ์ฐธ์กฐ(Reference)๋ฅผ ํตํด ์ฐ๊ฒฐ๋์ด ์์ต๋๋ค. ์ด ์ฐ๊ฒฐ ๊ตฌ์กฐ๊ฐ ๋ง์น ๊ฑฐ๋ฏธ์ค(Graph) ๊ฐ๋ค๊ณ ํ์ฌ ์ด๋ฅผ ๊ฐ์ฒด ๊ทธ๋ํ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
- ์ (Node) : ๊ฐ์ฒด (์:
Review,Member,Store) - ์ (Edge) : ์ฐธ์กฐ ๊ด๊ณ (์:
Review๋Member๋ฅผ ์๊ณ ์์) ์์ ์ฝ๋์์ ๊ฐ์ฒด ๊ทธ๋ํ ํ์์ ํด๋นํ๋ ๋ถ๋ถ์ ์๋์ ๊ฐ๋ค.
review.getMember().getName()
// 1. review ๊ฐ์ฒด์์ (์์)
// 2. getMember()๋ฅผ ํตํด ์ฐ๊ฒฐ๋ Member ๊ฐ์ฒด๋ก ์ด๋ (ํ์)
// 3. Member ๊ฐ์ฒด์ getName()์ ํธ์ถ (๊ฐ ํ๋)์ด์ฒ๋ผ .(์ )์ ์ฐ์ด์ ์ฐ๊ด๋ ๊ฐ์ฒด๋ก ๊ณ์ ๋ค์ด๊ฐ๋ ํ์๋ฅผ ๊ฐ์ฒด ๊ทธ๋ํ ํ์์ด๋ผ ํ ์ ์๋ค.
๊ฐ์ฒด ๊ทธ๋ํ ํ์์ ์ฃผ์ํ์ฌ์ผ ํ๋ ์ด์ ๋ ์ฑ๋ฅ ๋๋ฌธ์ด๋ค.
- ์ง์ฐ ๋ก๋ฉ (Lazy Loading): ๋ณดํต JPA์์
Review์Member๋ManyToOne๊ด๊ณ๋ก ์ฑ๋ฅ์ ์ํด ๋ช ์์ ์ผ๋ก ์ง์ฐ ๋ก๋ฉ(LAZY)์ ์ค์ ํ๋ค. - ํ์ ์ ์ฟผ๋ฆฌ ๋ฐ์ :
ReviewConverter์์review.getMember().getName()์ ํธ์ถํ๋ฉฐ ๊ฐ์ฒด ๊ทธ๋ํ๋ฅผ ํ์ํ๋ ์๊ฐ, JPA๋ ๋น์๋๋ ๋ฉค๋ฒ ์ ๋ณด๋ฅผ ์ฑ์ฐ๊ธฐ ์ํด DB์ SELECT ์ฟผ๋ฆฌ๋ฅผ ์ถ๊ฐ๋ก ๋ ๋ฆฐ๋ค. - N+1 ๋ฌธ์ : ๋ฐ๋ก ์ด ์ง์ ์์ N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๋ง์ฝ 10๊ฐ์ ๋ฆฌ๋ทฐ๊ฐ ์กด์ฌํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
- ๋ฆฌ๋ทฐ 10๊ฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํ ๋ฆฌ๋ทฐ ์ฟผ๋ฆฌ 1๊ฐ
- ๊ฐ ๋ฆฌ๋ทฐ๋ง๋ค ์์ฑ์์ ์ด๋ฆ์ ์์๋ด๊ธฐ ์ํด ์ถ๊ฐ์ ์ธ ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ โ 10๊ฐ
- ํ๋์ ์ฟผ๋ฆฌ๋ฅผ ์ํด 10๊ฐ์ ์ฟผ๋ฆฌ๊ฐ ์ถ๊ฐ์ ์ผ๋ก ๋ฐ์ํ๋ค
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด
@Query์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ ํจ์น ์กฐ์ธ์ ์ํ JPQL๋ฌธ์ ์ง์ ์์ฑํ๊ฑฐ๋ @EntityGraph ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์๋ค.