JpaPagingItemReader OFFSET 문제 해결 방법

러블리소피·2025년 1월 7일
public class JpaFixedPagingItemReader<T> extends JpaPagingItemReader<T> {

    @Override
    public int getPage() {
        return 0;
    }
}

JpaFixedPagingItemReader에서 getPage() 메서드를 오버라이드하여 항상 페이지 번호를 0으로 고정하는 방식은 일반적인 페이징 처리 로직을 무력화하는 방식이라 문제가 발생할 가능성이 높습니다.

📌 문제의 핵심

  • JpaPagingItemReader는 내부적으로 페이징 방식으로 데이터를 읽어옵니다. 즉, 페이지 번호(page)와 페이지 크기(pageSize)를 사용하여 쿼리를 실행합니다.
  • 항상 getPage()가 0을 반환하면 매번 첫 번째 페이지의 데이터를 반복해서 읽게 되어 무한 루프가 발생하거나 같은 데이터를 중복 처리하는 문제가 생깁니다.

⚠️ 예상되는 문제

✅ 왜 이런 코드가 작성됐을까?

아마도 중간에 데이터가 변경되거나 삭제될 때 발생하는 OFFSET 문제를 회피하려고 getPage()를 0으로 고정하는 방법을 고려한 것 같습니다.
하지만 이 방법은 문제를 해결하는 것이 아니라, 페이징 로직을 비정상적으로 변경하여 새로운 문제를 유발할 가능성이 높습니다.

✅ 해결 방법 제안

JpaPagingItemReader 사용 시 OFFSET 기반 페이징 문제를 해결하려면 다음과 같은 방법을 고려하세요.

1️⃣ WHERE 조건을 사용하여 페이지 이동

페이징에 OFFSET을 사용하는 대신, 페이징 기준 필드(id)를 조건으로 사용하는 방식으로 쿼리를 최적화할 수 있습니다.

@Bean
public JpaPagingItemReader<Entity> jpaPagingItemReader(EntityManagerFactory entityManagerFactory) {
    return new JpaPagingItemReaderBuilder<Entity>()
        .name("jpaPagingItemReader")
        .entityManagerFactory(entityManagerFactory)
        .queryString("SELECT e FROM Entity e WHERE e.id > :lastId ORDER BY e.id ASC")
        .parameterValues(Map.of("lastId", 0)) // 처음엔 0, 이후에는 마지막 처리된 ID로 변경
        .pageSize(1000)
        .build();
}
  • 첫 번째 페이지의 lastId는 0으로 시작하고, 이후 페이지에서는 마지막으로 처리된 ID 값을 기준으로 조건을 변경해 데이터를 가져오면 됩니다.

2️⃣ Cursor 기반 처리로 전환

JpaPagingItemReader 대신 Cursor 방식을 사용하면 OFFSET 문제를 피할 수 있습니다.

@Bean
public JpaCursorItemReader<Entity> jpaCursorItemReader(EntityManagerFactory entityManagerFactory) {
    return new JpaCursorItemReaderBuilder<Entity>()
        .name("jpaCursorItemReader")
        .entityManagerFactory(entityManagerFactory)
        .queryString("SELECT e FROM Entity e ORDER BY e.id ASC")
        .build();
}

Cursor 방식은 데이터를 한 번에 로드하지 않고 스트리밍 방식으로 처리하므로 대용량 데이터 처리 시 효율적입니다.

✅ 정리

  • getPage()를 항상 0으로 고정하는 것은 페이징 로직을 무력화하는 잘못된 접근입니다.
  • OFFSET 문제를 해결하려면 페이징 기준 필드를 활용한 WHERE 조건 방식이나 Cursor 방식을 사용하는 것이 권장됩니다.

이 방법들이 더 안정적이고 성능에도 좋습니다! 😊

profile
발전하는 개발자가 되고싶어요

0개의 댓글