본문 바로가기
SpringBoot/오류

SpringBatch JpaPagingReader 조건을 통한 조회 시 문제점과 해결방안

by se0nghyun2 2024. 5. 3.

데이터 추출을 위한 조건을 통한 조회 시 아래와 같은 문제가 발생하였다.

(chunkSize,PageSize는 모두 1로 가정)

 

문제

MailHistory테이블의 flg값이 X인 애들을 모두 O로 변경하는 배치 작업을 구현하였으나 띄엄띄엄 업데이트가 되는 상황을 마주하였다.

 

배치 실행 전(왼쪽),배치 실행 후(오른쪽)

 

 

 

기존 코드

MailHistory엔티티

@Entity
public class MailHistoryEntity extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long historyNo;

    ...

    private String flg;
}

 

이메일 재발송 배치 Config

@Slf4j
@Configuration
@RequiredArgsConstructor
public class EmailRetryBatchConfig {
    private final EntityManagerFactory entityManagerFactory;
    private final MailService mailService;
    private int chunkSize=1;

    @Bean
    public Job emailRetryJob(PlatformTransactionManager transactionManager, JobRepository jobRepository){
        return new JobBuilder("emailRetryJob",jobRepository)
                .start(emailRetryStep(transactionManager,jobRepository))
                .build()
                ;
    }

    public Step emailRetryStep(PlatformTransactionManager transactionManager, JobRepository jobRepository){
        return new StepBuilder("emailRetryStep",jobRepository)
                .<MailHistoryEntity,MailHistoryEntity>chunk(chunkSize,transactionManager)
                .reader(emailRetryReader(null))
                .processor(emailRetryProcessor())
                .writer(emailRetryWriter())
                .build()
                ;
    }

    @Bean
    @StepScope
    public JpaPagingItemReader<MailHistoryEntity> emailRetryReader(@Value("#{jobParameters[nowDt]}") String nowDt){
        log.info("emailRetryReader start");

        JpaPagingItemReader<MailHistoryEntity> reader =  new JpaPagingItemReader<>();
        reader.setPageSize(chunkSize);
        reader.setParameterValues(parameterMap);
        reader.setName("emailRetryReader");
        reader.setEntityManagerFactory(entityManagerFactory);
        reader.setQueryString("select m from MailHistoryEntity m where flg='X' order by historyNo");
        
        return reader;
    }

    @Bean
    public ItemProcessor<MailHistoryEntity,MailHistoryEntity> emailRetryProcessor(){
        log.info("emailRetryProcessor start");
        return item -> {
            log.info("이메일 재발송 처리");
            
            item.sendSuccess();

            return item;
        };
    }

    @Bean
    public ItemWriter<MailHistoryEntity> emailRetryWriter(){
        log.info("emailRetryWriter start");

        JpaItemWriter<MailHistoryEntity> writer = new JpaItemWriter<>();
        writer.setEntityManagerFactory(entityManagerFactory);
    }


}

 

 

문제 발생 원인

조회 조건 존재 시 Paging의 대한 문제이다.

 

페이지 조회 쿼리

 

 

 

페이징 별 데이터 값을 살펴보자.

 

첫 페이징) limit 0,1

첫 페이징 조회 시 조회 조건에 해당하는 데이터들 중 limit 0,1 조회 시 HistoryNo 393에 해당하는 로우데이터가 조회된다.

노란색 범위(페이징 대상), 빨간색 범위(조회 대상)


그리고 해당 데이터는 업데이트가 된다.

 

 

두번째 페이징) limit 1,1

노란색 범위(페이징 대상), 빨간색 범위(조회 대상)

두번째 페이징에선 조회 조건에 해당하는 데이터들 중 limit 1,1 조회 시 396 데이터가 조회되어 해당 데이터 업데이트한다. 

의도대로라면 393~397 내에서 조회되어 페이징 처리되어야 하나 조회 조건으로 인해 394~397 내에서 조회되어 처리된다.

 

해결

1.Cursor 

Jpa는 지원되지 않아 따로 실제 구현은 하지 않음

 

2. PagingReader Override

첫번째,두번째, 그 이후 페이지 모두 대상 데이터 조회 시 이미 업데이트된 데이터 제외하고 조회되므로 시작값을 0으로 둘 수 있도록 한다. (limit 0,1 으로 고정)

@Bean
@StepScope
public JpaPagingItemReader<MailHistoryEntity> emailRetryReader(@Value("#{jobParameters[nowDt]}") String nowDt){
    log.info("emailRetryReader start");

    //override 통한 문제 해결
    JpaPagingItemReader<MailHistoryEntity> reader = new JpaPagingItemReader<MailHistoryEntity>() {
        @Override
        public int getPage() {
            return 0;
        }
    };

    reader.setPageSize(chunkSize);
    reader.setParameterValues(parameterMap);
    reader.setName("emailRetryReader");
    reader.setEntityManagerFactory(entityManagerFactory);
    reader.setQueryString("select m from MailHistoryEntity m where createdDt=:nowDt and flg='X' order by historyNo");
    return reader;
}

 

 

위와 같이 수정 후 배치 수행 시 모두 정상적으로 업데이트 성공하였다.


 

참고

https://jojoldu.tistory.com/337

 

Spring Batch Paging Reader 사용시 같은 조건의 데이터를 읽고 수정할때 문제

안녕하세요. 이번 시간에는 Spring Batch를 사용하시는 분들이 자주 묻는 질문 중 하나인 같은 조건의 데이터를 읽고 수정할때 어떻게 해야하는지 에 대해서 소개드리려고 합니다. 모든 코드는 Githu

jojoldu.tistory.com