해결된 질문
작성
·
529
0
안녕하세요 영한님! 페이징과 한계돌파 부분을 수강하면서 질문하고 싶은 내용이 생겨 남기게 되었습니다.
default_batch_fetch_size=n 으로 지정할 경우, 컬렉션에서 n개씩 값을 가져오는 것으로 이해하였습니다.
코드로 그 과정을 살펴보면,
List<OrderDto> result = orders.stream()
.map(o -> new OrderDto(o))
을 통해서 각각의 order를 순회하면서 OrderDto의 생성자를 호출하고, 생성자 안에서
orderItems = order.getOrderItems().stream()
.map(orderItem -> new OrderItemDto(orderItem))
이렇게 orderItem을 순회하면서 OrderItemDto를 만들고,
public OrderItemDto(OrderItem orderItem) {
itemName = orderItem.getItem().getName();
orderPrice = orderItem.getOrderPrice();
count = orderItem.getCount();
}
최종적으로 OrderItemDto의 생성자 안에서 orderItem.getItem().getName() 를 호출하면서 orderItem과 그 안의 Item이 지연로딩되는 것으로 이해하였습니다.
그렇다면 JPA는 default_batch_fetch_size=n으로 인해 어떤 n개의 orderItem을 쿼리로 요청할지 결정해야 하는데, 이는 어떠한 방식으로 이루어지는 것인가요?
위와 같이 iteration을 돌면서 요청 보낼 orderItem의 id를 하나하나 모았다가 n개가 다 차게 되면 쿼리를 보내는 식인지, 아니면 다른 방식으로 결정이 되는 것인지 궁금합니다!
답변 4
0
앗 그렇군요! 지금 살펴보니 쿼리 -> 10개 출력 -> 쿼리 -> 10개 출력... 순서로 되어있는 게 맞습니다!
Hibernate:
select
orderitems0_.order_id as order_id5_5_1_,
orderitems0_.order_iem_id as order_ie1_5_1_,
orderitems0_.order_iem_id as order_ie1_5_0_,
orderitems0_.count as count2_5_0_,
orderitems0_.item_id as item_id4_5_0_,
orderitems0_.order_id as order_id5_5_0_,
orderitems0_.order_price as order_pr3_5_0_
from
order_item orderitems0_
where
orderitems0_.order_id in (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
orderItem count : 1
orderItem count : 2
orderItem count : 3
orderItem count : 4
orderItem count : 5
orderItem count : 6
orderItem count : 7
orderItem count : 8
orderItem count : 9
orderItem count : 10
Hibernate:
select
orderitems0_.order_id as order_id5_5_1_,
orderitems0_.order_iem_id as order_ie1_5_1_,
orderitems0_.order_iem_id as order_ie1_5_0_,
orderitems0_.count as count2_5_0_,
orderitems0_.item_id as item_id4_5_0_,
orderitems0_.order_id as order_id5_5_0_,
orderitems0_.order_price as order_pr3_5_0_
from
order_item orderitems0_
where
orderitems0_.order_id in (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
orderItem count : 11
orderItem count : 12
orderItem count : 13
orderItem count : 14
orderItem count : 15
orderItem count : 16
orderItem count : 17
orderItem count : 18
orderItem count : 19
orderItem count : 20
...
그런데, 아직도 이해가 어려운 것은
미리 default_batch_fetch_size 만큼의 데이터를 가져오기 위해서는 어떤 데이터가 미래에 사용하는 데이터인지를 알아야 하는 것 아닌가요..?!
그렇지 않다면 단순히 id기준으로 뒤의 default_batch_fetch_size개 데이터를 가져오는 것인가요?
0
Jaden Kim님 테스트하고 공유해주셔서 감사합니다^^
그런데 JPA는 버퍼처럼 모아두고 쿼리를 하는 것이 아니라 미리 쿼리를 합니다.
1,2,3,4,5,6,7,8,9,10 이렇게 데이터가 있고 batchsize=5라면
1을 조회하는 순간 1,2,3,4,5를 미리 조회해두고
이후 6을 조회하는 순간 6,7,8,9,10을 조회합니다.
이 부분은 지연로딩을 조회하기 직전에 로그를 남겨보시면 확인할 수 있습니다.
감사합니다.
0
말씀해주신대로 테스트를 해봤습니다!
InitDb에서 아래의 코드로 Order에 OrderItem을 한개씩 등록하여 총 100개의 주문을 생성했습니다
for (int i = 1; i <= 100; i++) {
OrderItem orderItem1 = OrderItem.createOrderItem(book1, 10000, i);
Order order = Order.createOrder(member, delivery, orderItem1);
em.persist(order);
}
default_batch_fetch_size=10 으로 지정했고, OrderApiController의 코드를 아래와 같이 for문으로 풀어쓰고
System.out을 통해 어떤 식으로 쿼리가 발생하는지 확인했습니다
for (OrderItem orderItem : order.getOrderItems()) {
OrderItemDto orderItemDto = new OrderItemDto(orderItem);
System.out.println("orderItem count : " + orderItem.getCount());
list.add(orderItemDto);
}
이때, count를 1~100의 숫자로 순차적으로 저장했기 때문에, getCount()를 통해 몇번째 orderItem이 출력되고 있는지 확인했습니다.
아래의 코드를 통해서 각각의 order를 순회하면서 위 코드를 호출하게 되고, orderItem을 하나씩 지연로딩 시킵니다
for (Order order : orders) {
result.add(new OrderDto(order));
}
결과는 아래와 같습니다
orderItem count : 1
orderItem count : 2
orderItem count : 3
orderItem count : 4
orderItem count : 5
orderItem count : 6
orderItem count : 7
orderItem count : 8
orderItem count : 9
orderItem count : 10
Hibernate:
select
orderitems0_.order_id as order_id5_5_1_,
orderitems0_.order_iem_id as order_ie1_5_1_,
orderitems0_.order_iem_id as order_ie1_5_0_,
orderitems0_.count as count2_5_0_,
orderitems0_.item_id as item_id4_5_0_,
orderitems0_.order_id as order_id5_5_0_,
orderitems0_.order_price as order_pr3_5_0_
from
order_item orderitems0_
where
orderitems0_.order_id in (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
orderItem count : 11
orderItem count : 12
orderItem count : 13
orderItem count : 14
orderItem count : 15
orderItem count : 16
orderItem count : 17
orderItem count : 18
orderItem count : 19
orderItem count : 20
Hibernate:
select
orderitems0_.order_id as order_id5_5_1_,
orderitems0_.order_iem_id as order_ie1_5_1_,
orderitems0_.order_iem_id as order_ie1_5_0_,
orderitems0_.count as count2_5_0_,
orderitems0_.item_id as item_id4_5_0_,
orderitems0_.order_id as order_id5_5_0_,
orderitems0_.order_price as order_pr3_5_0_
from
order_item orderitems0_
where
orderitems0_.order_id in (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
...
테스트 결과, 지연로딩이 발생해야 하는 객체를 버퍼처럼 10개씩 모아놨다가, default_batch_fetch_size로 지정한 개수가 다 차게 되면 쿼리가 발생하는 것을 확인했습니다!
감사합니다 :)
0
안녕하세요. Jaden Kim님
위와 같이 iteration을 돌면서 요청 보낼 orderItem의 id를 하나하나 모았다가 n개가 다 차게 되면 쿼리를 보내는 식인지, 아니면 다른 방식으로 결정이 되는 것인지 궁금합니다!
-> 이 부분을 한번 테스트 해보시면 더 많은 것을 이해하실 수 있을거에요^^!
단순히 for로 바꾸어서 System.out으로 지연 로딩 전에 찍어보시면 어떤 타이밍에 쿼리가 나가는지 확실히 이해하실 수 있을거에요.
테스트 해보시고 결과를 남겨주세요^^
감사합니다.
하이버네이트는 본인이 조회한 데이터를 알고 있습니다.
예를 들어서 a -> b 관계로 엔티티가 있을 때 select로 a를 100개 조회했습니다.
그러면 내부에서 a1 ~ a100을 조회했다는 것을 알고 있습니다.
이제 a1.getB()을 조회할 때 a1~a10을 in 쿼리를 사용해서 b 10개를 한번에 조회할 수 있습니다.
감사합니다.