본문 바로가기
스프링

[스프링 부트와 JPA 활용] API 개발과 성능 최적화

by moonstal 2022. 7. 3.

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();

컬렉션 조회 최적화

  1. 엔티티를 DTO로 변환 (지연로딩 쿼리 계속나감)

     //OrderDto
     orderItems = order.getOrderItems().stream()
     .map(orderItem -> new OrderItemDto(orderItem))
     .collect(toList());
    
     //OrderItemDto
     itemName = orderItem.getItem().getName();
  2. 페치 조인 최적화( 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());
  3. 페이징과 한계 돌파

  • 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();
  1. JPA에서 DTO 직접 조회

     //toOne관계 먼저
     OrderQueryDto(o.id, m.name, o.orderDate, o.status, d.address)
    
     //루프돌면서 컬렉션 추가
     OrderItemQueryDto(oi.order.id, i.name, oi.orderPrice, oi.count)
  2. 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 분리
  • 서비스 계층에서 트랜잭션 유지

링크

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-API%EA%B0%9C%EB%B0%9C-%EC%84%B1%EB%8A%A5%EC%B5%9C%EC%A0%81%ED%99%94

'스프링' 카테고리의 다른 글

[스프링 부트와 JPA 활용] 웹 애플리케이션 개발  (0) 2022.06.22
파일 업로드  (0) 2022.06.21
타입 컨버터  (0) 2022.06.20
예외 처리  (0) 2022.06.19
로그인  (0) 2022.06.18