API 개발과 성능 최적화
API 개발 기본
@RestController, @RequestBody
엔티티 Request Body에 직접 매핑-> 검증로직 추가, 엔티티 변경시 API 스펙 바뀜->DTO 필요
//컨트롤러 List<MemberDto> collect = findMembers.stream() .map(m -> new MemberDto(m.getName())) //DTO로 변환 .collect(Collectors.toList()); return new Result(collect); //컬렉션 감싸서 넘기기 @Data @AllArgsConstructor static class Result<T> { private T data; }
API 개발 고급
기본
- 지연 로딩 N+1 쿼리 실행 order.getMember().getName();
- 페치 조인 최적화
select o from Order o join fetch o.member m join fetch o.delivery d
- JPA에서 DTO로 바로 조회: 재사용성 떨어짐
//조회 전용 리포지토리 em.createQuery( "select new jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto(o.id, m.name, o.orderDate, o.status, d.address)" + " from Order o" + " join o.member m" + " join o.delivery d", OrderSimpleQueryDto.class) .getResultList();
컬렉션 조회 최적화
엔티티를 DTO로 변환 (지연로딩 쿼리 계속나감)
//OrderDto orderItems = order.getOrderItems().stream() .map(orderItem -> new OrderItemDto(orderItem)) .collect(toList()); //OrderItemDto itemName = orderItem.getItem().getName();
페치 조인 최적화( 1대다 조인시 컬렉션 때문에 order중복->distinct->페이징 불가 )
//OrderRepository "select distinct o from Order o" + " join fetch o.member m" + " join fetch o.delivery d" + " join fetch o.orderItems oi" + " join fetch oi.item i" //OrderApiController List<OrderDto> result = orders.stream() .map(o -> new OrderDto(o)) .collect(toList());
페이징과 한계 돌파
ToOne관계 페치조인,
컬렉션 지연 로딩,
hibernate.default_batch_fetch_size:size 만큼 IN 쿼리로 조회
쿼리 1 + 1
@RequestParam(value = "offset",defaultValue = "0") int offset, @RequestParam(value = "limit", defaultValue = "100") int limit //OrderItem 빼고 em.createQuery( "select o from Order o" + " join fetch o.member m" + " join fetch o.delivery d", Order.class) .setFirstResult(offset) .setMaxResults(limit) .getResultList();
JPA에서 DTO 직접 조회
//toOne관계 먼저 OrderQueryDto(o.id, m.name, o.orderDate, o.status, d.address) //루프돌면서 컬렉션 추가 OrderItemQueryDto(oi.order.id, i.name, oi.orderPrice, oi.count)
JPA에서 DTO 직접 조회 - 컬렉션 조회 최적화(ToOne 관계조회-> id list만들어 in 쿼리에 넣기)
API 개발 고급 - 실무 필수 최적화
OSIV ON
- Open Session In View: 기본 true
- 최초 데이터베이스 커넥션 시작~API 응답 끝까지 영속성 컨텍스트와 데이터베이스 커넥션 유지
OSIV OFF
- spring.jpa.open-in-view: false
- 트랜잭션 종료시 같이 종료
- 커넥션 리소스 낭비x
- Command와 Query 분리
- 서비스 계층에서 트랜잭션 유지