query를 날릴 때 distinct 사용시 페이징 처리를 할 수 없다는 단점이 있다.
대신 개 빠름.
그럼 페이징 처리를 하기 위해선 어떤 방식으로 해결 할 수 있을까?
우선 Order 라는 클래스가 아래와 같이 정의 되었다고 할 때
class Order{
private Long orderId;
private Member member;
private Delivery delivery;
private List<Item> items;
}
Order 페이징 처리정보를 받아오기 위해선 distinct를 사용해서 아래와 같이 query를 날리면 된다.
public List<Order> findAllOrders() {
return em.createQuery( "select distinct o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d" +
" join fetch o.Items i" +
" join fetch i.item it", Order.class)
.getResultList();
}
distinct 의 많은 장점에도 불구하고 페이징 처리가 불가능 하기 때문에 페이징 처리를 하기 위해선 다른 방식으로 query를 날려야 한다.
우선 Order 정보를 담을 새로운 클래스인 OrderDto 클래스를 생성하고 Order 안의 Item 정보를 담을 ItemDto 클래스도 생성한다고 하자. (ItemDto 클래스 생성은 귀찮아서 생략. )
@Data
static class OrderDto{
private Long orderId;
private Member member;
private Delivery delivery;
private List<ItemDto> items;
public OrderDto(Order order){
orderId = order.getOrderId();
member = order.getMember();
delivery = order.getDelivery();
items = order.getItems().stream()
.map(item -> new ItemDto(item))
.collect(toList());
}
}
이제 데이터 정보를 받아올 함수를 생성하고
public List<OrderDto> getOrder(int offset, int limit){
List<Order> orders = em.createQuery("select o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d", Order.class)
.setFirstResult(offset)
.setMaxResults(limit)
.getResultList();
List<OrderDto> orderDtos = orders.stream()
.map(o -> new OrderDto(o))
.collect(toList());
return orderDtos;
}
마지막으로 설정정보 변경을 통해 완료한다.
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 1000 #숫자 변경
이런 방식으로 query를 생성하게 되면 페이징 처리와 1+N 문제를 1+1로 최적화 시킬 수 있다.
디테일하게 부분적으로 적용하고 싶을 때는 Order class의 items에 직접 batchsize를 적용하면 된다.
@BatchSize(size = 50)
@OneToMany(mappedBy = "order", cascade = CascadeTypa.ALL)
private List<Item> items = new ArrayList<>();