스프링 배치 가이드
- 지난 포스팅에서 튜토리얼 보고 따라해봤는데, 이번에는 개념부터 천천히 공부해보자.
- 책을 보고 공부하려 했으나, 스프링과 부트의 배치 사용 문법이 많이 달라 이동욱님의 블로그를 보고 공부했다.
http://devhooney.tistory.com/134
1. Simple Job 생성하기
@EnableBatchProcessing
@SpringBootApplication
public class SpringBatchApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBatchApplication.class, args);
}
}
- @EnableBatchProcessing
Spring Batch 기능 활성화
@Configuration
@Slf4j
@RequiredArgsConstructor
public class SimpleJobConfiguration {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Job simpleJob() {
return jobBuilderFactory.get("simpleJob")
.start(simpleStep1())
.build();
}
@Bean
public Step simpleStep1() {
return stepBuilderFactory.get("simpleStep1")
.tasklet((contribution, chunkContext) -> {
log.info("Step1!!!!");
return RepeatStatus.FINISHED;
})
.build();
}
}
- jobBuilderFactory.get("simpleJob")
simpleJob이라는 이름으로 Job을 생성
- stepBuilderFactory.get("simpleStep1")
simpleStep1이라는 이름으로 Step을 생성
- tasklet()
- Step 안에서 수행될 기능을 명시
- tasklet은 Step 안에서 단일로 수행될 커스텀한 기능을 선언할 때 사용
배치의 구조인데,
Job은 Step으로 구성되어 있고, Step은 위 그림엔 없지만, Item ~ 들과 tasklet로 구성되어 있다.
이상태로 실행하면
2022-12-09 09:39:23.850 INFO 9520 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{}]
2022-12-09 09:39:23.873 INFO 9520 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [simpleStep1]
2022-12-09 09:39:23.879 INFO 9520 --- [ main] c.e.s.job.SimpleJobConfiguration : Step1!!!!
2022-12-09 09:39:23.883 INFO 9520 --- [ main] o.s.batch.core.step.AbstractStep : Step: [simpleStep1] executed in 10ms
잘 실행된다.
여기까지는 지난번 Spring.io 의 튜토리얼과 거의 같은 난이도.
2. MariaDB와 Spring Batch 실행하기
- Spring Batch는 메타 데이터 테이블이 필요하다.
- 메타데이터에는
- 이전에 실행한 job
- 최근 실패한 batch parameter가 무엇이고, 성공한 것은 무엇인지
- 다시 실행하면 어디서부터 시작할 지
- 어떤 job에는 어떤 step이 있는지
- step들 중 성공한 step과 실패한 step
등의 데이터가 담겨있다.
이러한 테이블들을 직접 생성해줘야 한다.
Spring Batch에 해당 스키마가 존재하므로 복사해서 만들어주면 된다.
귀찮을테니 쿼리를 저장
-- Autogenerated: do not edit this file
CREATE TABLE BATCH_JOB_INSTANCE (
JOB_INSTANCE_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT ,
JOB_NAME VARCHAR(100) NOT NULL,
JOB_KEY VARCHAR(32) NOT NULL,
constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
) ENGINE=InnoDB;
CREATE TABLE BATCH_JOB_EXECUTION (
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT ,
JOB_INSTANCE_ID BIGINT NOT NULL,
CREATE_TIME DATETIME(6) NOT NULL,
START_TIME DATETIME(6) DEFAULT NULL ,
END_TIME DATETIME(6) DEFAULT NULL ,
STATUS VARCHAR(10) ,
EXIT_CODE VARCHAR(2500) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED DATETIME(6),
JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL,
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
) ENGINE=InnoDB;
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
JOB_EXECUTION_ID BIGINT NOT NULL ,
TYPE_CD VARCHAR(6) NOT NULL ,
KEY_NAME VARCHAR(100) NOT NULL ,
STRING_VAL VARCHAR(250) ,
DATE_VAL DATETIME(6) DEFAULT NULL ,
LONG_VAL BIGINT ,
DOUBLE_VAL DOUBLE PRECISION ,
IDENTIFYING CHAR(1) NOT NULL ,
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;
CREATE TABLE BATCH_STEP_EXECUTION (
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
VERSION BIGINT NOT NULL,
STEP_NAME VARCHAR(100) NOT NULL,
JOB_EXECUTION_ID BIGINT NOT NULL,
START_TIME DATETIME(6) NOT NULL ,
END_TIME DATETIME(6) DEFAULT NULL ,
STATUS VARCHAR(10) ,
COMMIT_COUNT BIGINT ,
READ_COUNT BIGINT ,
FILTER_COUNT BIGINT ,
WRITE_COUNT BIGINT ,
READ_SKIP_COUNT BIGINT ,
WRITE_SKIP_COUNT BIGINT ,
PROCESS_SKIP_COUNT BIGINT ,
ROLLBACK_COUNT BIGINT ,
EXIT_CODE VARCHAR(2500) ,
EXIT_MESSAGE VARCHAR(2500) ,
LAST_UPDATED DATETIME(6),
constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;
CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT TEXT ,
constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
) ENGINE=InnoDB;
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
SERIALIZED_CONTEXT TEXT ,
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
) ENGINE=InnoDB;
CREATE TABLE BATCH_STEP_EXECUTION_SEQ (
ID BIGINT NOT NULL,
UNIQUE_KEY CHAR(1) NOT NULL,
constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;
INSERT INTO BATCH_STEP_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_STEP_EXECUTION_SEQ);
CREATE TABLE BATCH_JOB_EXECUTION_SEQ (
ID BIGINT NOT NULL,
UNIQUE_KEY CHAR(1) NOT NULL,
constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;
INSERT INTO BATCH_JOB_EXECUTION_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_EXECUTION_SEQ);
CREATE TABLE BATCH_JOB_SEQ (
ID BIGINT NOT NULL,
UNIQUE_KEY CHAR(1) NOT NULL,
constraint UNIQUE_KEY_UN unique (UNIQUE_KEY)
) ENGINE=InnoDB;
INSERT INTO BATCH_JOB_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp where not exists(select * from BATCH_JOB_SEQ);
3. Batch_job_instance
테이블 생성 하고 실행 구성을 mysql용으로 하나 만들어주고(기존 것 복사해서 이름, profile명 변경) 실행하면 잘된다.
실행 후
select * from batch_job_instance;
쿼리를 실행하면 데이터가 들어있다.
이 테이블은 Job Parameter에 따라 생성되는 테이블이다.
Job Paramter는 배치가 실행될 때 외부에서 받을 수 있는 파라미터이다.
같은 Job이라도 Job Parameter가 다르면 테이블에 저장되며, Job Parameter가 같으면 저장되지 않는다.
테스트를 위해서 코드를 수정하고
@Bean
public Job simpleJob() {
return jobBuilderFactory.get("simpleJob")
// .start(simpleStep1())
.start(simpleStep1(null))
.build();
}
@Bean
@JobScope
// public Step simpleStep1() {
public Step simpleStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
return stepBuilderFactory.get("simpleStep1")
.tasklet((contribution, chunkContext) -> {
log.info("Step1!!!!");
log.info("requestDate = {}", requestDate);
return RepeatStatus.FINISHED;
})
.build();
}
@JobScope는 Step 선언문에서만 사용 가능.
Scope는 스프링 컨테이너에서 빈이 관리되는 범위이다.
- singleton, prototype, request, session, application이 있으며 기본은 singleton으로 생성된다.
구성편집에서 프로그램인수(Program argument)를 넣어준다.
실행을 하면
인수가 잘 넘어가서 로그에 찍혔다.
다시 batch_job_instance를 보면
select * from batch_job_instance;
데이터가 추가 되었다.
한 번더 실행했을 때 추가되는 지 보면
에러가 난다.
파라미터를 바꿔서 실행하면
잘되고,
데이터도 들어가 있다.
결론적으로 동일한 Job이 Job Parameter가 달라지면 그때마다 BATCH_JOB_INSTANCE에 생성되며, 동일한 Job Parameter는 여러개 존재할 수 없다.
- 참고
'개발 > Java&Kotlin' 카테고리의 다른 글
[Spring] 스프링 배치(Spring Batch) 가이드 따라가기 (3) (0) | 2022.12.13 |
---|---|
[Spring] 스프링 배치(Spring Batch) 가이드 따라가기 (2) (0) | 2022.12.11 |
[Spring] 스프링 배치(Spring Batch) 맛보기 (1) | 2022.12.06 |
[Kotlin] 코틀린 + 스프링부트 + JPA 사용해보기 (0) | 2022.12.02 |
[Spring] 스프링 부트에서 Spring Rest Docs 적용하기 (0) | 2022.11.30 |