프로젝트/개인 프로젝트(2023.11.13-2023.12.18)

[개인프로젝트] 리팩토링 - Spring Batch Paging Reader 같은 조건 데이터 조회안됨

dal_been 2024. 1. 29. 15:39
728x90

개인프로젝트 리팩토링 하다가 스프링 배치코드가 조금 더럽길래...ㅎㅎ 테스트 코드랑 같이 리팩토링 하는데 데이터를 20개를 가지고 테스트해봤더니 10개만 적용되는 문제가 발생했다...

 


문제상황

 

같은 조건으로 reader에서 데이터를 조회하는데 초반에 10개만 batch가 적용되고 나머지 10개에 대해서 적용이 되지 않았다..

  @Bean
  public JpaPagingItemReader<AdjustWalkerInfo> adjustReader(){
    Map<String, Object> parameter = new HashMap<>();
    parameter.put("status", WalkerServiceStatus.FINISH);
    parameter.put("payStatus", PAY_DONE);

    return new JpaPagingItemReaderBuilder<AdjustWalkerInfo>()
        .name("adjustReader")
        .entityManagerFactory(entityManagerFactory)
        .pageSize(chunkSize)
        .queryString("SELECT NEW com.project.dogwalker.batch.adjust.dto.AdjustWalkerInfo(u, ph, w) "
        + "FROM WalkerReserveServiceInfo w "
        + "JOIN FETCH w.payHistory ph "
        + "JOIN FETCH w.walker u "
        + "WHERE w.status = :status "
        + "AND ph.payStatus = :payStatus")
        .parameterValues(parameter)
        .build();
  }

 

reader의 경우 이렇게 되어있고

    for(int i=0;i<19;i++){
      WalkerReserveServiceInfo reserveServiceInfo = WalkerReserveServiceInfo.builder()
          .customer(user)
          .walker(walker)
          .serviceDateTime(LocalDateTime.now().plusHours(i))
          .timeUnit(50)
          .status(FINISH)
          .servicePrice(1000)
          .build();
      reserveServiceRepository.save(reserveServiceInfo);

      PayHistory payHistory = PayHistory.builder()
          .customer(user)
          .payPrice(1000)
          .payMethod("CARD")
          .walkerReserveInfo(reserveServiceInfo)
          .build();

      payHistoryRespository.save(payHistory);

    }

 

테스트 코드의 경우 이렇게 되어있었다. 따라서 19개의 데이터가 모두 adjust테이브에 들어가야하지만 10개만 적용되는 문제가 발생했다.

음 원래는 20000L(21000L오타입니다..)가 나와야하지만...뭔가 이상하다..

 

원인??

 

Paging행위 자체가 문제라고한다.

Paging은 offset과 limit을 이용하여 매 조회마다 다음 페이지를 읽어오는 방식이 이야기 한다.

 

여기서 초반에 1-10까지의 데이터를 조회한다음 데이터를 update를 진행하였다.

그렇다면 다음 batch가 적용될 데이터는 10개만 남는다.

다시 batch 쪽에서 검색 쿼리를 진행하면 offset 0자체가 11부터 시작해야한다. 왜냐면 조회쿼리에서는 결국 이전 데이터는 update되었기때문에 해당하지 않기 때문이다.

 

그러나 Paging 쿼리 자체는 offset 11 부터 10개를 검색한다.

즉 처음에 데이터가 update되었기 때문에 다음데이터를 다시 0부터 조회해야하는데 11부터 데이터를 조회하니 없는 것이다.

 

 

해결방법

 

PagingReader Override하자

 

  @Bean
  public JpaPagingItemReader<AdjustWalkerInfo> adjustReader(){
    Map<String, Object> parameter = new HashMap<>();
    parameter.put("status", WalkerServiceStatus.FINISH);
    parameter.put("payStatus", PAY_DONE);

    JpaPagingItemReader<AdjustWalkerInfo> reader = new JpaPagingItemReader <>(){
      @Override
      public int getPage() {
        return 0;
      }
    };

    reader.setName("adjustReader");
    reader.setEntityManagerFactory(entityManagerFactory);
    reader.setPageSize(chunkSize);
    reader.setQueryString("SELECT NEW com.project.dogwalker.batch.adjust.dto.AdjustWalkerInfo(u, ph, w) "
        + "FROM PayHistory ph "
        + "JOIN FETCH ph.walkerReserveInfo w "
        + "JOIN User u On w.walker.userId = u.userId "
        + "WHERE w.status = :status "
        + "AND ph.payStatus = :payStatus");
    reader.setParameterValues(parameter);
    return reader;

  }

 

Update 될때마다 대상 데이터 범위가 줄어드니 page번호를 변경시키지 않고 10번쨰로 고정시키는 것이다. 

 

그렇게 했더니 테스트 성공...!

 


다행히 스프링배치 적용할때 jojoldu블로그를 유심히 봐서 저 내용이 기억이 났다.. 그래서 빠르게 해결가능했다는..ㅎㅎ

 

https://jojoldu.tistory.com/337