인프런 커뮤니티 질문&답변

심정진님의 프로필 이미지
심정진

작성한 질문수

코드로 배우는 React with 스프링부트 API서버

서비스계층과 컨트롤러(4)-상품삭제

productRepository.selectList 호출시 이미지 리스트를 List객체로 반환되는 방법을 알고 싶습니다.

작성

·

167

0

productRepository.selectList 호출시 이미지 리스트를 List객체로 반환되는 방법을 알고 싶습니다.

 

아래의 코드를 보면 이미지리스트는 한개(pi.ord=0)만 가져오는데요.

imageList의 모든값이 List객체에 담겨 Page<Object[]>에 포함되는 방법을 알고 싶습니다.

 

Page<Object[]> result = productRepository.selectList(pageable);
@Query("select p, pi from Product p left join p.imageList pi where pi.ord = 0 and p.delFlag = false")
Page<Object[]> selectList(Pageable pageable);

 

답변 1

0

구멍가게코딩단님의 프로필 이미지
구멍가게코딩단
지식공유자

우선 Object[]로 처리한다면 동일한 상품 데이터와 다른 이미지 데이터들이 SQL의 결과로 나오기 때문에 이를 DTO로 처리할 때 분리해서 처리해야만 합니다.

@Query("select p, pi  from Product p left join p.imageList pi  where pi.ord >= 0 and p.delFlag = false ")
Page<Object[]> selectList2(Pageable pageable);

이렇게 되면 결과는 상품 1, 이미지 여러 개가 아래처럼 나오게 됩니다.

image 

 

차라리 이런 경우에는 다음과 같은 방법을 고려해 보시는 게 좋습니다.

 

이미지의 ord조건에 관계없이 만든다면

@Query("select p from Product p left join p.imageList pi  where p.delFlag = false ")
Page<Product> selectListWitAll(Pageable pageable);

처럼 만들 수 있습니다만..

 

이렇게 하면 테스트 코드를 아래와 같은 형태로 작성하게 됩니다. @Transaction 주의

@Transactional
@Test
public void testListWithAll() {

  //org.springframework.data.domain 패키지
  Pageable pageable = PageRequest.of(0, 10, Sort.by("pno").descending());

  Page<Product> result = productRepository.selectListWitAll(pageable);

  //java.util
  result.getContent().forEach(product ->{

    log.info(product);
    log.info(product.getImageList());

  });

}

문제는 이 상황에서 N+1문제가 발생하는데요..

Product를 가져올때 이미지는 가져오지 않기 때문에 10개의 상품 목록을 처리할 때 하나의 상품당

 

Hibernate:

select

i1_0.product_pno,

i1_0.file_name,

i1_0.ord

from

product_image_list i1_0

where

i1_0.product_pno=?

과 같은 쿼리가 실행되어서 총 11번의 쿼리가 실행되는 문제가 생깁니다.

 

이 문제를 막기 위해서는 Product에 @BatchSize를 지정하실 수 있습니다.

@ElementCollection
@Builder.Default
@BatchSize(size = 20)
private List<ProductImage> imageList = new ArrayList<>();

이렇게 되면 이미지들을 한번에 모아서 가져오게 되면서 아래와 같은 쿼리가 한번 더 실행되는 수준으로 끝나게 됩니다.

select

i1_0.product_pno,

i1_0.file_name,

i1_0.ord

from

product_image_list i1_0

where

i1_0.product_pno in (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)

 

아무리 Lazy Loading이 아닌 Eager Loading을 이용하더라도 여러 번 쿼리가 날아가기 때문에 @BatchSize를 이용하시는게 제일 무난합니다.

 

심정진님의 프로필 이미지
심정진

작성한 질문수

질문하기