작성
·
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, 이미지 여러 개가 아래처럼 나오게 됩니다.
차라리 이런 경우에는 다음과 같은 방법을 고려해 보시는 게 좋습니다.
이미지의 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를 이용하시는게 제일 무난합니다.