이를 해결하기 위해 “지연로딩 + Batch 전략”을 사용
default_batch_fetch_size: 100
을 application.yml에 추가
@GetMapping("/api/likebeers/{id}")
public WrapperClass showLikeBeers(@PathVariable("id") Long userid){
User findUser = userService.findOne(userid); //1번 user 조회
List<LikeBeer> likeBeers = findUser.getLikeBeers();
List<Beer> beers = new ArrayList<>();
for (LikeBeer likeBeer : likeBeers) { //2번 likebeer 조회
beers.add(likeBeer.getBeer());
System.out.println("likeBeer.getBeer() = " + likeBeer.getBeer());
}
//3번 beer 조회
List<BeerDto> beerDtos = beers.stream().map(b -> new BeerDto(b)).collect(Collectors.toList());
return new WrapperClass(beerDtos); //api의 확장이 가능하도록 wrapper 클래스로 감싸서 리스트를 return
}
User findUser = userService.findOne(userid)
에서 userid에 해당하는 user 조회 시 select 쿼리 발생likeBeer.getBeer()
수행 시 likeBeer 조회 쿼리 발생map(b -> new BeerDto(b)
DTO로 변환 시 Beer 엔티티 값에 접근하므로 beer를 조회하는 쿼리가 likeBeer 수 만큼 발생(N+1문제!)@GetMapping("/api/likebeers/{id}")
public WrapperClass showLikeBeers(@PathVariable("id") Long userid){
//fetch join 사용
List<LikeBeer> likeBeers = likeBeerService.findAllWithBeer(userid);
List<Beer> beers = new ArrayList<>();
for (LikeBeer likeBeer : likeBeers) {
beers.add(likeBeer.getBeer());
System.out.println("likeBeer.getBeer() = " + likeBeer.getBeer());
}
List<BeerDto> beerDtos = beers.stream().map(b -> new BeerDto(b)).collect(Collectors.toList());
return new WrapperClass(beerDtos); //api의 확장이 가능하도록 wrapper 클래스로 감싸서 리스트를 return
}
결론적으로 sql문을 대폭 줄일 수 있었다…!