上文已经搭建好了springboot的基本框架。现在开始加入spring batch功能–将txt的数据导入数据库。
批处理的流程,简单来讲就是,读取文件–执行业务逻辑–写入文件。spring batch对应这三个步骤的是三个接口ItemReader,ItemProcessor,和ItemWriter。但是不是只有这三个接口就行了,如下图所示:
job就是一整个封装的批处理实体。一个job有一个或多个step,每个step都必须包含读取文件–执行业务逻辑–写入文件这三个步骤。但是光有job不行,还要启动job,也就是JobLaunch。同时,job执行过程中,执行的是哪个job,执行到了第几条,执行是否成功,执行途中失败了如果知道是在第几条失败等等相关问题,都需要持久性存储起来。所以还需要一个JobRepository来存储有关当前正在运行的进程的元数据。
关于Job,有两个概念JobInstance和JobExecution。每运行一次Job,就会产生一个JobInstance。JobInstance会记录在BATCH_JOB_INSTANCE表中,同一个JobInstance可能会执行多次,这些记录在BATCH_JOB_EXECUTION相关表中。举个例子,需要每天从data.csv中读取数据并存入数据库。这显然只有一个Job,但是需要每天都执行,那么每天都有一个JobInstance,这个Job就会对应多个JobInstance,这些JobInstance通过JobParameters来区分。假如今天的JobInstance执行失败,明天需要继续执行,那今天的JobInstance就会对应两个JobExection。
对于Step,由于Step是包含在Job之中,当一个Step运行时,会产生一个StepExecution,这个StepExecution是与JobExecution对应的,BATCH_STEP_EXECUTION表中有字段JOB_EXECUTION_ID。
一、初始化batch框架
创建batch配置类BatchConfiruration.java,
@EnableBatchProcessing
@Configuration
@Slf4j
public class BatchConfiguration {
private final BookJpa bookJpa;
@Autowired
public BatchConfiguration(BookJpa bookJpa) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
this.bookJpa = bookJpa;
}
}
重点是@EnableBatchProcessing和@Configuration两个注解。
同时在application。properties中添加
spring.batch.initialize-schema=always
这样运行程序时就会自动创建batch相关的表。没有业务需要的话,不必自定义JobLaunch与JobReposity,这些都可以由框架自动配置,我们只需要专注于Job和Step的配置
二、配置Job
一个Job,有三点需要配置----名称,包含的step的顺序,以及什么时候需要重新启动。
spring batch框架提供了JobBuilderFactory来方便我们创建一个job,因此我们需要装配JobBuilderFactory,查看源码,可以发现其中只有一个get方法,用于设置一个JobBuilder。
public class JobBuilderFactory {
private JobRepository jobRepository;
public JobBuilderFactory(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
/**
* Creates a job builder and initializes its job repository. Note that if the builder is used to create a @Bean
* definition then the name of the job and the bean name might be different.
*
* @param name the name of the job
* @return a job builder
*/
public JobBuilder get(String name) {
JobBuilder builder = new JobBuilder(name).repository(jobRepository);
return builder;
}
}
所以过程就是,先用JobBuilderFactory创建一个JobBuilder,再用JobBuilder创建一个Job。
@Bean
public Job bookImportJop(@Qualifier("bookJobListener") JobExecutionListener jobListener
, @Qualifier("step1") Step step1) {
return jobBuilderFactory.get("bookImportJob")
.listener(jobListener)
.start(step1).buil