1. 의존성 추가 (H2 예제)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
2. 작업 수행 정보를 저장할 테이블 생성
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)
);
CREATE TABLE BATCH_JOB_EXECUTION (
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
VERSION BIGINT NOT NULL,
JOB_INSTANCE_ID BIGINT NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL,
START_TIME TIMESTAMP DEFAULT NULL,
END_TIME TIMESTAMP DEFAULT NULL,
STATUS VARCHAR(10),
EXIT_CODE VARCHAR(2500),
EXIT_MESSAGE VARCHAR(2500),
LAST_UPDATED TIMESTAMP NOT NULL,
JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL,
constraint JOB_INST_EXEC_FK foreign key(JOB_INSTANCE_ID)
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
);
3. 작업 수행 정보를 저장할 JobRepository 생성
JobRepository - 작업 수행 정보를 저장하기 위한 인터페이스
이 인터페이스를 구현한 JobRepositoryFactoryBean을 사용하여 JobRepository를 생성
@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
@Autowired
private DataSource dataSource;
@Bean
public JobRepository jobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager());
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public JobLauncher jobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
// ...
}
4. 작업 수행 정보를 저장할 JobExecutionListener 구현
JobExecutionListener -작업 수행 전후에 호출되는 메서드를 정의하는 인터페이스
이 인터페이스를 구현하여 작업 수행 정보를 데이터베이스에 저장
public class MyJobExecutionListener implements JobExecutionListener {
private final JobRepository jobRepository;
@Autowired
public MyJobExecutionListener(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
@Override
public void beforeJob(JobExecution jobExecution) {
JobInstance jobInstance = jobExecution.getJobInstance();
jobRepository.createJobExecution(jobInstance, jobExecution.getJobParameters(), null);
}
@Override
public void afterJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
jobRepository.update(jobExecution);
}
}
}
위의 코드에서는 JobExecutionListener 인터페이스를 구현하여 beforeJob 메소드와 afterJob 메소드를 오버라이드한다.
beforeJob 메소드는 작업이 실행되기 전에 호출되며, JobExecution의 정보를 이용하여 JobRepository를 사용하여 JobExecution을 생성
afterJob 메소드는 작업이 완료된 후에 호출되며, JobExecution의 상태가 COMPLETED인 경우 JobRepository를 사용하여 JobExecution을 업데이트
JobExecution의 상태 및 작업에 대한 정보를 데이터베이스에 저장하게 됨
Spring Batch는 JPA를 지원하기 때문에 JPA를 사용하여 BATCH_JOB_INSTANCE 및 BATCH_JOB_EXECUTION과 같은 테이블을 엔티티로 매핑할 수 있다.
일반적으로 Spring Batch는 EntityManagerFactory를 통해 JPA를 구성한다.
그리고 JobRepository 구현체를 구성할 때 EntityManagerFactory를 사용하여 Batch Metadata 정보를 DB에 저장한다
@Entity
@Table(name = "BATCH_JOB_INSTANCE")
public class BatchJobInstance {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JOB_INSTANCE_ID")
private Long jobInstanceId;
@Column(name = "JOB_NAME")
private String jobName;
@Column(name = "JOB_KEY")
private String jobKey;
@OneToMany(mappedBy = "jobInstance", cascade = CascadeType.ALL, orphanRemoval = true)
private List<BatchJobExecution> jobExecutions = new ArrayList<>();
// getters and setters
}
@Entity
@Table(name = "BATCH_JOB_EXECUTION")
public class BatchJobExecution {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "JOB_EXECUTION_ID")
private Long jobExecutionId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "JOB_INSTANCE_ID", referencedColumnName = "JOB_INSTANCE_ID")
private BatchJobInstance jobInstance;
@Column(name = "CREATE_TIME")
private Date createTime;
@Column(name = "START_TIME")
private Date startTime;
@Column(name = "END_TIME")
private Date endTime;
@Column(name = "STATUS")
private String status;
// getters and setters
}