스프링데이터 + JPA/API 개발 17

17. OSIV 성능 최적화

하이버네이트 : Open Session In View JPA는 Open EntityManager In View 라고 함. 트래픽 많은 서비스에서는 장애가 날 수 있음. 이걸 알아야 함. 스프링 시작할 때, 남기는 WARN이 하나 있다. 2023-11-17T06:33:36.261+09:00 WARN 8448 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to..

16. Dto로 조회. 플랫 데이터 최적화 쿼리 하나

컬렉션인 OrderItem까지도 join해서 쿼리 하나로 가져오는 거다. sql로 정말 flat하게 조회 해와야 한다 @Data public class OrderFlatDto { private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; private String itemName; private int orderPrice; private int count; } 저렇게 OrderItem의 내용들까지고 펼쳐놔서 flat하게 만들 것이다. 일단 그러면 가져오려면 public List findAllByDto_flat() { retur..

15. Dto 직접조회 컬렉션 최적화

지금은 컬렉션도 각각 Dto로 조회해오면서, batch가 안 먹히게 되었다. (정확히 등록된 엔티티를 조회해와야만 되는 듯 하다(fetch 한것 등)) 그래서 지금 컬렉션은 ToOne이 아니라서 row 뻥튀기를 일으키게 하지 않기 위해 따로 넣어줬다. 그래서 이렇게 OrderItem을 넣어줄 때마다 또 그 OrderItem을 조회해주는 쿼리가 n번 나가게 되었다. 이제는 저 OrderItem 조회하는 걸 쿼리를 한번만 나가게끔 만들 것이다. @GetMapping("/api/v5/orders") public List ordersV5(){ return orderQueryRepository.findAllByDto_optimization(); } public List findAllByDto_optimizatio..

14. 컬렉션 Dto로 직접 조회

화면에 fit한 데이터들 찾는 용도의 Repository는 따로 패키지및 클래스를 만든다. @GetMapping("/api/v4/orders") public List ordersV4(){ return orderQueryRepository.findOrderQueryDtos(); } public List findOrderQueryDtos() { List result = findOrders(); result.forEach((o)->{ List orderItems = findOrderItems(o.getOrderId()); o.setOrderItems(orderItems); }); return result; } 여러 메소드로 나눠서 조회했다. ToOne?과 ToMany는 따로 조회했다. 이유는 new 오퍼레이션..

13. 컬렉션 페이징 한계돌파

컬렉션 패치조인은 결국 JPA는 데이터를 일단 다 가지고 와 메모리에서 페이징을 하기 때문에, 데이터가 많을 경우 out of memory도 날 수 있고 생각보다 굉장히 위험하다. 지금부터 페이징 + 컬렉션 엔티티 함께 조회하는 효율적인 방법을 알아보겠다. 먼저, ToOne관계는(즉 나에게 1인) 모두 join fetch한다. row수를 증가시키지 않는다. 그래서 페이징 해도 상관이 없다. 그 다음 컬렉션은 그냥 LAZY 로딩인 상태로 둔다. 여기서 뭔가 작업을 해 둘거다. 일단은, ToOne 관계는 그냥 join fetch해서 가져온다. @GetMapping("/api/v3.1/orders") public List ordersV3_page(){ List orders = orderRepository.fi..

12. 컬렉션 -> 엔티티 join fetch 최적화

그냥 join fetch 해서 가져올 거다. @GetMapping("/api/v3/orders") public List ordersV3(){ List orders = orderRepository.findAllWithItem(); return orders.stream() .map(o-> new OrderDto(o)) .collect(Collectors.toList()); } public List findAllWithItem() { return em.createQuery("select o from Order o" + " join fetch o.member m" + " join fetch o.delivery d" + " join fetch o.orderItems oi" + " join fetch oi.item..

11. 컬렉션 엔티티를 Dto로

@GetMapping("/api/v2/orders") public List ordersV2(){ List orders = orderRepository.findAllString(new OrderSearch()); return orders.stream() .map(o-> new OrderDto(o)) .collect(Collectors.toList()); } 변환 작업을 거쳐야 한다. OrderDto라는 것을 만들었다. 그런데, Order에 있는 OrderItems 또한 엔티티이다. 그래서 이것 또한 변환작업을 해야 한다. @Getter static class OrderDto{ private Long orderId; private String name; private LocalDateTime orderDat..

10. 컬렉션 조회 최적화

지금까지는 컬렉션 조회해오지는 않았음. 그런 것들의 경우 그냥 join fetch로 해결 가능 컬렉션 조회는 일대다 조회가 됨. 뭐 테이블도 대충 이런 느낌임. 일단 단계적으로 할거임. 마찬가지로 엔티티 직접 노출 먼저 할거임. @GetMapping("/api/v1/orders") public List ordersV1(){ List result = orderRepository.findAllString(new OrderSearch()); for (Order order : result) { order.getMember().getName(); order.getDelivery().getAddress(); List orderItems = order.getOrderItems(); for (OrderItem orde..

9. 바로 Dto로 받기

@GetMapping("/api/v4/simple-orders") public List ordersV4(){ return orderRepository.findOrderDtos(); } 바로 리포지토리에서 Dto로 가져오는 걸 정의하는 거다. public List findOrderDtos() { return em.createQuery("select new jpabook.jpashop.repository.OrderSimpleQueryDto(o.id, m.name, o.orderDate, o.status, d.address)" + " from Order o" + " join o.member m" + " join o.delivery d", OrderSimpleQueryDto.class) .getResultLis..

8. fetch join 최적화

@GetMapping("/api/v3/simple-orders") public List orderV3(){ List orders = orderRepository.findAllWithMemberDelivery(); List result = orders.stream() .map(o-> new SimpleOrderDto(o)) .collect(Collectors.toList()); return result; } 똑같은 데, 저 DB에서 가져오는 걸 findAllWithMemberDelivery()라는 걸 만들어서 가져올 거다. 메소드 이름이 거지같긴 한데, 보통은 주문이면 member와 delivery 가져와야 한다 이정도로 어느 정도 자주 쓰는 객체 그래프가 정해져 있기 때문에 그냥 findAll이라고 이름..