프로젝트/트러블슈팅

[Spring]무한 스크롤 + Enum 정렬 트러블슈팅

코딩로봇 2025. 4. 23. 19:51

intro

  • 프로젝트를 진행하며 발생한 문제 상황과 해결 과정들을 상세히 기록하고 추후에 같은 문제가 발생 했을때 빠르게 문제 해결하기 위해 트러블 슈팅을 정리할려고 한다.
  • 기록하는 습관을 기르기 위해 프로젝트 기간동안 꾸준히 작성할 것 이다.


배달 앱에서 메뉴 리스트를 무한 스크롤 방식으로 보여주기 위해 커서 기반 페이징을 도입했다. 하지만 카테고리 정렬, enum 사용, JPQL 커서 조건 등 다양한 문제에 부딪혔다.

 

⚠️ 1.문제 상황 발생

JPQL 을 이용하여 커서 기반 페이지네이션을 작성했다. JPQL에서 enum 메서드 사용 불가하여 오류가 발생했다.

 

Category.Enum

public enum Category {
    MAIN_MENU(1),
    SIDE_MENU(2),
    DRINK(3);

    private final int sortOrder;

    Category(int sortOrder) {
        this.sortOrder = sortOrder;
    }

 

MenuRepository 조회 - jpql 쿼리

@Query("""
    SELECT m FROM Menu m
    WHERE m.category.sortOrder > :categoryCursor
    ORDER BY m.category.sortOrder ASC, m.createdAt DESC
""")

 

🔎 2.원인 추론

@Query("""
    SELECT m FROM Menu m
    WHERE m.category.sortOrder > :categoryCursor
    ORDER BY m.category.sortOrder ASC
""")

 

찾아보니 sortOrder는 Enum 내부 필드이므로 JPQL에서 접근할 수 없다
JPQL은 Enum의 내부 메서드, 필드를 지원하지 않음.

 

 

📝  3.해결방안

EnumType.ORDINAL로 DB 저장 방식을 변경했다.

@Enumerated(EnumType.ORDINAL)
private Category category;

 

 

  • Enum이 0, 1, 2...로 DB에 저장된다
  • 정렬 및 비교가 가능해짐 (m.category > :categoryCursor)

 

 

📌4.결과 확인

 

최종 JPQL 쿼리

@Query("""
    SELECT m FROM Menu m
    WHERE (:categoryCursor IS NULL
           OR m.category > :categoryCursor
           OR (m.category = :categoryCursor AND m.id > :lastId))
    ORDER BY m.category ASC, m.id ASC
""")

 

정렬 기준을 category(ordinal) → id 순으로 설정해 무한 스크롤 시 데이터가 중복되거나 누락되지 않도록 하였다.

 

 

결과창

 

 

 

✒️회고

- 이번 트러블슈팅을 통해 JPQL에서는 Enum의 내부 필드나 메서드에 직접 접근할 수 없다는 점을 처음으로 명확히 알게 되었다.

 

- 평소 자바 코드에서는 자연스럽게 사용하던 getSortOrder()를 JPQL에서도 당연히 될 거라고 생각했지만, 실제로는 그게 아니었다.

 

- @Enumerated(EnumType.ORDINAL) 설정을 통해 enum 순서를 기준으로 정렬이 가능하게 만들었고, 이 덕분에 무한 스크롤 구현에 필요한 커서 기반 페이지네이션 로직도 깔끔하게 해결할 수 있었다.

 

- 앞으로는 JPQL을 작성할 때 enum 필드를 사용하게 된다면 반드시 DB 저장 방식부터 확인하고, ORDINAL이나 STRING 사용에 따라 쿼리 설계를 신중하게 해야겠다.