2. API 개발 고급 - 준비

shin·2024년 2월 18일

📜 성능 최적화 preview

  • 현업에서 성능이 나오지 않을 경우 튜닝이 필요함
  • 아래 항목이 최적화되지 않아서 성능 문제가 발생하는 경우가 많음

(1) 조회용 샘플 데이터 입력

  • 등록과 수정에서는 성능 문제가 많이 발생하지 않음
  • 조회시에 성능 문제가 크게 발생함

(2) 지연 로딩과 조회 성능 최적화

  • 고객이 API를 요청한 상황에서 다수의 쿼리가 나가는 경우 성능 문제가 발생할 수 있음

(3) 컬렉션 조회 최적화

  • db에서 조인을 했는데 데이터가 크게 늘어나지 않은 경우는 괜찮지만, 조인을 해서 데이터가 크게 늘어나면 성능 최적화가 어려워짐
  • 해당 상황에서의 jpa 최적화 공부

(4) 페이징과 한계 돌파

  • 일대다 조인을 해보면 데이터베이스 입장에서 데이터가 크게 늘어나기 때문에 제대로 페이징하기가 어려워짐
  • 만약 회원과 주문 테이블이 있을때, 회원을 기준으로 페이징을 하고 싶은데 주문과 조인을 하는 경우
  • 회원이 하나이고 주문이 두개이면 데이터가 두배로 증가되어 페이징하기가 어려워짐

(5) OSIV와 성능 최적화

  • OSIV : Open Session In-View
  • OSIV를 사용하는 경우 지연로딩이 편리해지고, 사용하지 않는 경우 Lazy Loading으로 인한 LazyInitializationException이 자주 발생하게 됨
  • LazyInitializationException 주요 원인 : JPA에서 관리하는 세션이 종료된 후에 관계가 설정된 엔티티를 참조하려고 할 때 발생함
    • Lazy Loading을 하려고 하는데 세션이 사라져서 프록시 초기화가 불가능해 지연로딩을 하지 못하는 경우에 발생하는 에러
  • 어떤 상황에 필요하고 필요하지 않은지 확인이 필요

💻 조회용 샘플 데이터 입력

  • API 개발 고급 설명을 위해 샘플 데이터 입력
  • 회원 1명 당 주문 2개 생성
    • userA
      • JPA1 BOOK
      • JPA2 BOOK
    • userB
      • SPRING1 BOOK
      • SPRING2 BOOK
package jpabook.jpashop;

import jakarta.annotation.PostConstruct;
import jakarta.persistence.EntityManager;
import jpabook.jpashop.domain.*;
import jpabook.jpashop.domain.item.Book;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@RequiredArgsConstructor
public class InitDb {

    private final InitService initService;

    @PostConstruct
    public void init() {
        initService.dbInit1();
        initService.dbInit2();
    }

    @Component
    @Transactional
    @RequiredArgsConstructor
    static class InitService {

        private final EntityManager em;

        public void dbInit1() {

            Member member = createMember("userA", "서울", "1", "1111");
            em.persist(member);

            Book book1 = createBook("JPA1 BOOK", 10000, 100);
            em.persist(book1);

            Book book2 = createBook("JPA2 BOOK", 20000, 100);
            em.persist(book2);

            OrderItem orderItem1 = OrderItem.createOrderItem(book1, 10000, 1);
            OrderItem orderItem2 = OrderItem.createOrderItem(book2, 20000, 2);
            Order order = Order.createOrder(member, createDelivery(member),
                    orderItem1, orderItem2);
            em.persist(order);

        }

        public void dbInit2() {

            Member member = createMember("userB", "진주", "2", "2222");
            em.persist(member);

            Book book1 = createBook("SPRING1 BOOK", 20000, 200);
            em.persist(book1);

            Book book2 = createBook("SPRING2 BOOK", 40000, 300);
            em.persist(book2);

            Delivery delivery = createDelivery(member);
            OrderItem orderItem1 = OrderItem.createOrderItem(book1, 20000, 3);
            OrderItem orderItem2 = OrderItem.createOrderItem(book2, 40000, 4);
            Order order = Order.createOrder(member, delivery, orderItem1,
                    orderItem2);
            em.persist(order);

        }

        private Member createMember(String name, String city, String street, String zipcode) {

            Member member = new Member();
            member.setName(name);
            member.setAddress(new Address(city, street, zipcode));

            return member;

        }
        private Book createBook(String name, int price, int stockQuantity) {

            Book book = new Book();
            book.setName(name);
            book.setPrice(price);
            book.setStockQuantity(stockQuantity);

            return book;

        }
        private Delivery createDelivery(Member member) {

            Delivery delivery = new Delivery();
            delivery.setAddress(member.getAddress());

            return delivery;

        }

    }

}
  • @Component 어노테이션을 선언해서 컴포넌트로 관리

    • 스프링의 컴포넌트 스캔
  • @PostConstruct

    • 의존성 주입이 이루어진 후 초기화를 수행하는 메서드
    • 해당 어노테이션이 붙은 메서드는 클래스가 서비스를 수행하기 전에 수행됨
    • 다른 리소스에서 호출되지 않아도 수행됨
    • 의존성 주입이 완료된 후에 실행되어야 하는 메서드에서 사용됨
    • 호출 순서
      • 생성자 호출 -> 의존성 주입 완료 -> @PostConstruct
    • 스프링 빈이 모두 올라오고 나면 스프링이 @PostContruct가 붙은 메서드 호출

조회용 샘플 데이터 입력 확인

  • 회원 목록

  • 상품 목록

  • 주문 내역

  • 주문 내역 화면에서는 회원당 주문 내역을 하나만 출력했으므로 하나만 노출됨


실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

profile
Backend development

0개의 댓글