대부분 스프링 배치의 내용은 '기억보다는 기록을' 블로그를 참고하여 공부하였습니다.
배치에 대해 공부하고자 하시는분은 이 글 보다 아래 블로그를 보는게 훨씬 도움이 됩니다
https://jojoldu.tistory.com/
2탄에서 해결 방법은 guppy님의 블로그를 참고하였습니다.
https://wckhg89.github.io/archivers/springbatch2
1탄 https://velog.io/@miz/Spring-Batch-%EC%82%BD%EC%A7%88%EA%B8%B0-1%ED%83%84
2021-05-29 ConcurrentHashMap 수정
singleton bean
을 사용하는 아이디어를 얻었다.ExecutionContext
를 사용할때 metaDataSchema에 데이터를 저장하면서 발생하는 시간 낭비와 저장공간 낭비를 해결 할 수 있다.@Component
@Slf4j
public class DataShareBean <T> {
private Map<String, T> shareDataMap;
public DataShareBean() {
this.shareDataMap = new ConcurrentHashMap<>();
}
public void putData(String key, T data) {
if(shareDataMap == null) {
log.debug("map is not initialize");
return;
}
shareDataMap.put(key, data);
}
public T getData (String key) {
if (shareDataMap == null) {
return null;
}
return shareDataMap.get(key);
}
/*
public void addData(String key, T data) {
if(shareDataMap == null) {
log.debug("map is not initialize");
return;
}
T t = shareDataMap.get(key);
if(t == null) {
shareDataMap.put(key,data);
return;
}
shareDataMap.put(key, (T) Long.valueOf((Long) data + (Long) t));
}
*/
//제가 concurrentHashMap을 잘못쓰고 있어서 추가적인 수정을 하겠습니다. (1)
public void addData(String key, T data) {
shareDataMap.compute(key,(k,v) -> (T) Long.valueOf((Long) data + (Long) v));
}
}
@Slf4j
@Configuration
@RequiredArgsConstructor
public class PayTotalJobThirdConfiguration {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
public static final String JOB_NAME = "PayTotalThirdJob";
public static final String BEAN_PREFIX = JOB_NAME + "_";
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final EntityManagerFactory entityManagerFactory;
private final TotalPayRepository totalPayRepository;
private final DataShareBean<Long> dataShareBean;
private final static int chunkSize = 1000;
@Bean(JOB_NAME)
public Job job() {
//제가 concurrentHashMap을 잘못쓰고 있어서 추가적인 수정을 하겠습니다. (2)
dataShareBean.putData("totalAmount", 0L);
return jobBuilderFactory.get(JOB_NAME)
.start(step(null))
.next(step2(null))
.build();
}
@Bean(BEAN_PREFIX + "step")
@JobScope
public Step step(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get(BEAN_PREFIX + "step")
.<Pay, Pay>chunk(chunkSize)
.reader(reader(null))
.writer(writer())
.build();
}
@Bean(BEAN_PREFIX + "reader")
@StepScope
public JpaPagingItemReader<Pay> reader(@Value("#{jobParameters[requestDate]}") String requestDate) {
return new JpaPagingItemReaderBuilder<Pay>()
.name(BEAN_PREFIX + "reader")
.entityManagerFactory(entityManagerFactory)
.pageSize(chunkSize)
.queryString("select p from Pay p where to_char(tx_date_time,'yyyy-mm-dd') = '" + requestDate + "'")
.build();
}
@Bean(BEAN_PREFIX + "writer")
@StepScope
public ItemWriter<Pay> writer() {
return list -> {
for(Pay pay : list) {
log.info("Current = {}", pay);
dataShareBean.addData("totalAmount", pay.getAmount());
}
};
}
@Bean(BEAN_PREFIX + "step2")
@JobScope
public Step step2(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get(BEAN_PREFIX + "step2")
.tasklet((contribution, chunkContext) -> {
TotalPay totalPay = new TotalPay(dataShareBean.getData("totalAmount"),requestDate);
totalPayRepository.save(totalPay);
return RepeatStatus.FINISHED;
}).build();
}
}