인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

인생은회전목마님의 프로필 이미지

작성한 질문수

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

주문 조회 V3.1: 엔티티를 DTO로 변환 - 페이징과 한계 돌파

(재질문)토이프로젝트에서 spring data jpa 기반으로 페이징 처리 중 궁금한 점 있습니다.

작성

·

165

0


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 아니오
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]

저번에도 같은 질문을 올렸다가 질문이 두서가 없다보니 여쭤보려고 한 것을 잘못 물어본거같아서 다시 질문드립니다. Spring Data JPA를 바탕으로 토이프로젝트를 개발하고있고 Pageable 인터페이스를 활용하고 있습니다.

 

프로젝트에서 Item(품목)의 하위 개념으로 Product(제품)을 가지고 있습니다.(1:N - 품목 하나에 대해 여러개의 제품을 등록 할 수 있음)

예를 들어 핸드폰이라는 Item(품목) 정보를 등록하고, 그 품목에 대한 Product(제품) ( 이를테면 아이폰10, 갤럭시S25, 샤오미)의 정보들을 등록합니다.

이때 특정 품목(itemId)을 클릭하면 해당 품목에 대한 정보와 내가 등록한 product 리스트가 띄어지도록 하는 api 기능을 구현하려 했습니다. 처음에는 요청이 item컨트롤러로 디스패치하고, product와 itemId를 기준으로 패치조인하여 데이터를 받아오는 식으로 구현을 했는데.. product리스트를 불러오는 과정에서 페이징을 하고자 기존의 로직을 수정하니, 메인i 테이블인 item을 기준으로 페이징이 되는 문제가 발생했습니다.

 

// page처리 시 문제가 발생하는 respository method

@Query(value = "SELECT DISTINCT i FROM Item i LEFT JOIN FETCH i.productList WHERE i.id = :itemId",

countQuery = "SELECT COUNT(p) FROM Product p WHERE p.item.id = :itemId")

Page<Item> findWithProductsByItemId(@Param("itemId") long itemId, Pageable pageable);

 

 

그래서 제가 생각한 두가지 안이 있는데 이중에 어떤 것으로 개발해야할지 판단이 잘 서지않아 질문드립니다.

 

1) 응용계층에서 item에 대한 정보를 불러오는 item서비스 호출 + 위 item에 해당되는 product 리스트 정보들을 paging 하여 불러오는 페이징하여 불러오는 product서비스 호출

 

2) product를 메인으로 item과 n:1 패치조인하는 메소드를 productRepository에서 생성.

 

1번 방법이 맞는 것 같지만,, paging으로 데이터를 불러올 때마다 item쿼리를 한번씩 날려야하는게 비효율적인거 같기도하고,, 2번으로 하자니... 구현하고자 하는 기능은 item을 메인으로 product 목록을 불러오는 것인데,, 실제 동작은 Product가 메인으로(Product컨트롤러로 디스패치) 처리가 되다보니 이렇게 해도 될까 하는 의문이 들었습니다.

이런 상황에서는 어떤 식으로 구현을 하는게 좋을지요. 고견을 여쭙니다 ㅠㅠ

답변 3

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 인생은회전목마님

이런 부분은 정답은 없지만 2번으로 해도 무방합니다. 왜냐하면 컨트롤러 -> 서비스 -> 리포지토리라는 구조에서 컨트롤러는 다양한 서비스를 호출할 수 있고, 서비스는 다양한 리포티토리를 호출할 수 있기 때문입니다.

컨트롤러(화면)에 맞추어 서비스, 리포지토리를 하나로 묶는 것이 딱 좋은 방법이라고는 할 수 없습니다.

감사합니다.

0

Matthew C님의 프로필 이미지

DB에 쿼리를 두 번 날리지만, 여러 곳에서 사용할 수 있는 게 효율적인지, 한방에 날려서 메모리에서 중복을 제거하는 게 효율적인지 메서드 활용 빈도와 PRODUCT 리스트의 사이즈 및 한 ROW 데이터의 크기 및 컬럼 수에 따라 다를 것 같은데, 프로젝트에 대한 설명으로만 유추해보자면, 저는 ITEM의 정보만 가져오는 곳과 PRODUCT 리스트만 불러오는 곳이 존재할 것 같아 보여요~

0

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인생은회전목마님, 인프런 AI 인턴입니다.

Spring Data JPA를 활용한 프로젝트에서 페이징 문제로 고민하시는 것 같습니다. 특히, Item과 Product의 관계를 중심으로 페이징 처리를 어떻게 해야 할지에 대해 고민하고 계시네요. 아래 설명으로 문제를 정리해보겠습니다.

  1. Item을 기준으로 조회하고 Product를 페이징할 경우:

    • Item 엔터티를 기준으로 Product 목록을 가져오면서 페이징을 구현하고 싶다면, 일반적으로 Item의 정보와 관련 Product 리스트를 각각 별도 서비스로 관리하는 것이 좋습니다. 이 방법은 데이터를 분리해서 가져옴으로써 불필요한 데이터 로딩을 방지할 수 있습니다.
    • 응용계층에서는 먼저 Item에 대한 정보를 가져오고, 그 다음에 해당 Item에 속한 Product 목록을 페이징 처리하여 가져오는 방법이 있습니다.
  2. Product를 기준으로 조회하여 Item과 연관 관계를 조인:

    • Product 중심으로 쿼리를 작성하고, Item과의 관계를 페치 조인해서 가져오는 방식은 Product를 기준으로 페이징을 할 수 있게 해줍니다.
    • 이렇게 구현하면 Product 엔터티가 메인이 되며, 페이징이 더욱 직관적입니다.
    • 장점은 해당 Product 리스트에 대한 페이징이 유리하다는 점입니다. 그러나 요건이 Item 중심이라면 구조가 왜곡될 수 있습니다.

관련된 사례와 답변을 참고하시면 문제 해결에 도움이 될 수 있습니다:

최종적으로는 데이터 모델링과 요구사항에 맞는 방향으로 결정하셔야 합니다. 일반적으로 복잡한 도메인의 경우, 각 기능에 맞는 서비스를 분리하여 성능과 유지보수성을 고려하는 것이 중요합니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.