public class JpaFixedPagingItemReader<T> extends JpaPagingItemReader<T> {
@Override
public int getPage() {
return 0;
}
}
JpaFixedPagingItemReader에서 getPage() 메서드를 오버라이드하여 항상 페이지 번호를 0으로 고정하는 방식은 일반적인 페이징 처리 로직을 무력화하는 방식이라 문제가 발생할 가능성이 높습니다.

아마도 중간에 데이터가 변경되거나 삭제될 때 발생하는 OFFSET 문제를 회피하려고 getPage()를 0으로 고정하는 방법을 고려한 것 같습니다.
하지만 이 방법은 문제를 해결하는 것이 아니라, 페이징 로직을 비정상적으로 변경하여 새로운 문제를 유발할 가능성이 높습니다.
JpaPagingItemReader 사용 시 OFFSET 기반 페이징 문제를 해결하려면 다음과 같은 방법을 고려하세요.
페이징에 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();
}
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 방식은 데이터를 한 번에 로드하지 않고 스트리밍 방식으로 처리하므로 대용량 데이터 처리 시 효율적입니다.
이 방법들이 더 안정적이고 성능에도 좋습니다! 😊