너무 안타깝지만, Spring Batch 5.0 버전은 스프링 배치 자체에 익숙해지고 나서 시작하려고 한다. 버전 마이그레이션에 집중하는 것보다는 현재는 스프링 배치 자체에 집중해야 할듯. 4버전으로 실습 한 후에, 마이그레이션 시리즈를 이어가려고 한다.
위 블로그에서 나온 내용들을 쭉 실습 할 생각이고, 추가적인 내용이 있으면 (추가하고 싶은 내용이 있다면) 더 적을 예정.
우선, 새 프로젝트를 부트해주고 의존성을 추가한다
제일 먼저 할 일은, 우리가 만든 프로젝트 어플리케이션에 Spring Batch 기본 설정 적용하는 것.
위와 같이 설정해주고, 시작해보자
@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfiguration {
private final JobBuilderFactory jobBuilderFactory; // 생성자 DI 받음
private final StepBuilderFactory stepBuilderFactory; // 생성자 DI 받음
@Bean
public Job simpleJob() {
return jobBuilderFactory.get("simpleJob")
.start(simpleStep1())
.build();
}
@Bean
public Step simpleStep1() {
return stepBuilderFactory.get("simpleStep1")
.tasklet((contribution, chunkContext) -> {
log.info(">>>>> This is Step1");
return RepeatStatus.FINISHED;
})
.build();
}
}
spring:
profiles:
active: mariadb
---
spring:
profiles:
active: local
datasource:
hikari:
jdbc-url: jdbc:h2:mem:db;MODE=MYSQL;
username: sa
password:
driver-class-name: org.h2.Driver
batch:
job:
enabled: true
---
spring:
profiles:
active: mariadb
datasource:
hikari:
jdbc-url: jdbc:mariadb://localhost:3306/commerce
// 본인에 맞는 url
username: 유저네임
password: 비밀번호
driver-class-name: org.mariadb.jdbc.Driver
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
show_sql: true
format_sql: true
batch:
job:
enabled: true
jdbc:
initialize-schema: always
yml 파일을 다음과 같이 작성한다.
batch:
job:
enabled: true
jdbc:
initialize-schema: always
마지막으로, 혹시 문제가 있는 경우 (BAD SQL EXCEPTION 등)
@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfiguration {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Job simpleJob() {
return jobBuilderFactory.get("simpleJob")
.start(simpleStep1(null))
.build();
}
@Bean
@JobScope
public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get("simpleStep1")
.tasklet((contribution, chunkContext) -> {
log.info(">>>>> This is Step1");
log.info(">>>>> requestDate = {}", requestDate);
return RepeatStatus.FINISHED;
})
.build();
}
}
위에서 작성한 실습 코드를 실행 해봤다면, 위와 같이 코드를 바꿔준다.
import org.springframework.beans.factory.annotation.Value;
이후에 실행할 경우, 다음 결과를 얻을 것이다
위와 같이 parameters = "우리가 설정한" 패러미터로 설정됨.
그리고 다시 돌려보면? 다음 에러를 만나게 된다.
Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={requestDate=20180805}. If you want to run this job again, change the parameters.
job instance가 이미 같은 패러미터로 존재한다!
-> 즉, JOB Parameter 당 한번의 실행이 보장된다 == 패러미터당 하나의 인스턴스 생성이 보장된다
다음으로 살펴 볼 것은 BATCH_JOB_EXECUTION 테이블.
BATCH_JOB_INSTANCE 테이블과 부모자식 관계.
JOB EXECUTION 테이블은 자신의 부모인 JOB INSTANCE가 실행/실패했던 모든 내역을 가진다.
위와 같이 시도한 두 개의 패러미터의 EXECUTION이 COMPLETE로 잘 저장되어 있는 모습.
@Slf4j // log 사용을 위한 lombok 어노테이션
@RequiredArgsConstructor // 생성자 DI를 위한 lombok 어노테이션
@Configuration
public class SimpleJobConfiguration {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Job simpleJob() {
return jobBuilderFactory.get("simpleJob")
.start(simpleStep1(null))
.next(simpleStep2(null))
.build();
}
@Bean
@JobScope
public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get("simpleStep1")
.tasklet((contribution, chunkContext) -> {
throw new IllegalArgumentException("step1에서 실패합니다.");
})
.build();
}
@Bean
@JobScope
public Step simpleStep2(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get("simpleStep2")
.tasklet((contribution, chunkContext) -> {
log.info(">>>>> This is Step2");
log.info(">>>>> requestDate = {}", requestDate);
return RepeatStatus.FINISHED;
})
.build();
}
}
다음과 같이 FAILED 상태와 함께 EXIT 메시지까지 매우 자세하게 나오는 모습.
여러번 시도해서 실패해도, EXECUTION은 위와 같이 쌓이고
해당 패러미터의 INSTANCE는 동일하다.
그렇다면 성공시켜볼까? 코드를 바꿔주자
// 이전코드
@Bean
@JobScope
public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get("simpleStep1")
.tasklet((contribution, chunkContext) -> {
throw new IllegalArgumentException("step1에서 실패합니다.");
})
.build();
}
// 이후코드
@Bean
@JobScope
public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get("simpleStep1")
.tasklet((contribution, chunkContext) -> {
log.info(">>>>> This is Step2");
log.info(">>>>> requestDate = {}", requestDate);
return RepeatStatus.FINISHED;
})
.build();
}
BATCH_EXECUTION 테이블을 봄녀
다음과 같이 COMPLETE 됨을 알 수 있다.
여기서 알 수 있는점
BATCH INSTANCE는 "실패"의 경우에는 같은 패러미터로 재시도 가능하다. 즉, 한 패러미터에 대해서 인스턴스가 "성공"하면 그 패러미터로는 중복 시도 불가
-> 여러번 시도해서 성공할 때만 저장 가능! (통계 데이터 등)
BATCH INSTANCE, BATCH EXECUTION 의 관계!
JOB Parameter에 알아본 시간.