spring batch 是什么
Spring Batch 作为 Spring 的子项目,是一款基于 Spring 的企业批处理框架。通过它可以构建出健壮的企业批处理应用。Spring Batch 不仅提供了统一的读写接口、丰富的任务处理方式、灵活的事务管理及并发处理,同时还支持日志、监控、任务重启与跳过等特性,大大简化了批处理应用开发,将开发人员从复杂的任务配置管理过程中解放出来,使他们可以更多地去关注核心的业务处理过程。
什么时候使用 spring batch
当需要做大批量的数据处理时,例如:
- 无需用户交互即可最有效地处理大量信息的自动化,复杂处理。 这些操作通常包括基于时间的事件(例如月末计算,通知或通信)。
- 在非常大的数据集中重复处理复杂业务规则的定期应用(例如,保险利益确定或费率调整)。
- 集成从内部和外部系统接收的信息,这些信息通常需要以事务方式格式化,验证和处理到记录系统中。 批处理用于每天为企业处理数十亿的交易。
spring batch 结构
- 首先,Spring Batch运行的基本单位是一个Job,一个Job就做一件批处理的事情。
- 一个Job包含很多Step,step就是每个job要执行的单个步骤。
- Step里面,会有Tasklet,Tasklet是一个任务单元,它是属于可以重复利用的东西。
- 然后是Chunk,chunk就是数据块,你需要定义多大的数据量是一个chunk。
- Chunk里面就是不断循环的一个流程,读数据,处理数据,然后写数据。Spring Batch会不断的循环这个流程,直到批处理数据完成。
Chunk
Spring batch在配置Step时采用的是基于Chunk的机制,即每次读取一条数据,再处理一条数据,累积到一定数量后再一次性交给writer进行写入操作。这样可以最大化的优化写入效率,整个事务也是基于Chunk来进行。
比如我们定义chunk size是50,那就意味着,spring batch处理了50条数据后,再统一向数据库写入。
chunk前面需要定义数据输入类型和输出类型,如果不定义这个类型,会报错。
.<Message, Message>chunk(CHUNK_SIZE)
Reader
Reader顾名思义就是从数据源读取数据。
Spring Batch给我们提供了很多好用实用的reader,基本能满足我们所有需求。比如FlatFileItemReader,JdbcCursorItemReader,JpaPagingItemReader等。也可以自己实现Reader。
Processor
需要定义输入和输出的类型,把输入I通过某些逻辑处理之后,返回输出O。
public interface ItemProcessor<I, O> {
O process(I item) throws Exception;
}
Writer
Writer顾名思义就是把数据写入到目标数据源里面。
Spring Batch同样给我们提供很多好用实用的writer。比如JpaItemWriter,FlatFileItemWriter,HibernateItemWriter,JdbcBatchItemWriter等。同样也可以自定义。
Listener
Spring Batch同样实现了非常完善全面的listener,listener很好理解,就是用来监听每个步骤的结果。比如可以有监听step的,有监听job的,有监听reader的,有监听writer的。
Skip
Spring Batch提供了skip的机制,也就是说,如果出错了,可以跳过。如果你不设置skip,那么一条数据出错了,整个job都会挂掉。
设置skip的时候一定要设置什么Exception才需要跳过,并且跳过多少条数据。如果失败的数据超过你设置的skip limit,那么job就会失败。
你可以分别给reader和writer等设置skip机制。
writer(testWriter).faultTolerant().skip(Exception.class).skipLimit(SKIP_LIMIT)
Retry
这个和Skip是一样的原理,就是失败之后可以重试,你同样需要设置重试的次数。
同样可以分别给reader,writer等设置retry机制。
如果同时设置了retry和skip,会先重试所有次数,然后再开始skip。比如retry是10次,skip是20,会先重试10次之后,再开始算第一次skip。
搭建 spring batch 代码
pom引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
配置类
@Configuration
@EnableAutoConfiguration
@EnableBatchProcessing(modular = true)
public class SpringBatchConfiguration {
@Bean
public ApplicationContextFactory testJobContext() {
return new GenericApplicationContextFactory(TestJobConfiguration.class);
}
}
@EnableBatchProcessing是打开Batch。如果要实现多Job的情况,需要把EnableBatchProcessing注解的modular设置为true,让每个Job使用自己的ApplicationConext。
TestDataBean 数据类
@Entity
@Table(name = "testDataBean ")
public class TestDataBean {
@Column(name = "id", nullable = false)
private Integer Id;
。。。
}
TestJobConfiguration
public class TestJobConfiguration {
// 注入job工厂
@Autowired
private JobBuilderFactory jobBuilderFactory;
// 注入step工厂
@Autowired
private StepBuilderFactory stepBuilderFactory;
// 得到job bean
@Bean
public Job testJob(@Qualifier("TestStep") Step testStep) {
return jobBuilderFactory.get("testJob")
.start(testStep)
.build();
}
// 得到job中的step的bean
@Bean
public Step testStep(@Qualifier("testReader") FlatFileItemReader<TestDataBean> testReader,
@Qualifier("testWriter") JpaItemWriter<TestDataBean> testWriter,
@Qualifier("errorWriter") Writer errorWriter) {
return stepBuilderFactory.get("testStep")
.<TestDataBean , TestDataBean>chunk(CHUNK_SIZE)
.reader(testReader)
.listener(new TestReadListener(errorWriter))
.processor(testProcessor)
.writer(testWriter)
.listener(new TestWriteListener())
.build();
}
// readerBean 读取数据
@Bean
public FlatFileItemReader<TestDataBean> testReader() {
FlatFileItemReader<TestDataBean> reader = new FlatFileItemReader<>();
reader.setResource(new FileSystemResource(new File(TEST_FILE)));
return reader;
}
// processorBean 处理数据
@Bean
public PersonItemProcessor processor() {
return new PersonItemProcessor();
}
// writerBean 写入数据
@Bean
public JpaItemWriter<TestDataBean> testWriter() {
JpaItemWriter<TestDataBean> writer = new JpaItemWriter<>();
return writer;
}
}
运行Job
首先我们通过运行起来的Spring application得到jobRegistry,然后通过job的名字找到对应的job。
接着,我们就可以用jobLauncher去运行这个job了,运行的时候会传一些参数,可以解决重复执行同一个job的问题。
JobRegistry jobRegistry = context.getBean(JobRegistry.class);
Job job = jobRegistry.getJob(jobName);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
JobExecution jobExecution = jobLauncher.run(job, createJobParams());
Spring Batch数据表
batch_job_instance:这张表能看到每次运行的job名字。
batch_job_execution:这张表能看到每次运行job的开始时间,结束时间,状态,以及失败后的错误消息是什么。
batch_step_execution:这张表你能看到更多关于step的详细信息。比如step的开始时间,结束时间,提交次数,读写次数,状态,以及失败后的错误信息等。