1. 简介
Spring Batch 用于大数据量的批处理任务,是一种轻量级的批处理框架。当数据量超过百亿级时,还是要用海量数据处理框架handoop。Spring Batch具有简便、轻盈、容易集成等优点,而且提供了多种Writer 和 Reader借口,让开发者专注于业务处理,Spring Batch负责流程。业务场景: 定期执行、消息驱动、并行处理、手动重启、顺序执行。
特点:轻量级、高健壮、提供开发效率
a. 丰富的开箱即用组件(Reader、Writer),减少开发时间
b. 面向Chunk的处理(写入针对批,兼顾效率和可靠性)
c. 事务管理能力
d. 元数据管理
e. 易监控的批处理应用
f. 丰富的流程定义
g. 健壮的应用特性(跳过,重试,重启)
h. 易扩展
i. 可灵活复用先用的IT资产(通过Adapter封装)
基本概念:
2. Job
Job,顾名思义,就是一个任务,是Spring Batch的最小业务单元。它往往是由多个Step构成,
这些Step按照一定的次序组织在一个Job中。Job具有一些配置参数:
1. Job的名称
2. 定义或者排序Step
3. 配置Job是否可以重新启动
2.1 JobInstance
每个Job的运行实例,Job每执行一次就是一个JobInstance。
2.2 JobParameters
与JobInstance绑定,指定JobInstance的运行参数,如执行时间等。
2.3 JobExecution
是JobInstance的一次运行,运行结果为失败或者成功。注意一个JobInstance的一次完整运行,则JobExecution必须是成功的,否则还会是同一个JobInstance。
3. Step
一个Job是由多个Step构成,是批处理的最小单位的执行单元。
3.1 StepExecution
是Step的一次运行,类似于JobExecution。但是不同之处在于,如果一个StepExecution失败了,那么下一个Step将不会拥有StepExecution。
4. ExecutionContext
这是一个Key-Value的集合,是用来对JobExecution和StepExecution的执行状态的储存。一般情况下用来进行restart操作。
一个JobExecution对应一个ExectionContext,而所有的StepExecution共有一个StepExection。
5 JobRepository
是对所有Job、Step的持久化操作。当一个Job启动后,一个JobExection就会从JobRepository中获得。
其它概念还有JobLaucher、ItemReader、ItemWriter、ItemProcessor等,这里不做介绍了。
更多信息请参考官网:https://docs.spring.io/spring-batch/trunk/reference/html/index.html
本文主要就一个demo进行介绍
3. 实例Demo
使用MyBatis框架,进行read和write。当然也可以使用JdbcTemplate进行同样的操作。
单独定义一个ItemWriter
@Component public class UserBatchWriter implements ItemWriter<User>, BeanPostProcessor { private Logger logger = LoggerFactory.getLogger(UserBatchWriter.class); @Autowired private UserDao userDao; @Autowired private JdbcTemplate userJdbcTemplate; @Override public void write(List<? extends User> list) throws Exception { logger.info("list:"+ Arrays.toString(list.toArray())); System.out.println("write thread:"+ Thread.currentThread().getName()); userDao.updateAllUsers(list); } }
然后对批处理进行配置
package com.qd.almo.hilearning.config; import com.qd.almo.hilearning.batch.BatisCursorItemReader; import com.qd.almo.hilearning.batch.BatisPagingItemReader; import com.qd.almo.hilearning.batch.UserBatchWriter; import com.qd.almo.hilearning.dao.UserDao; import com.qd.almo.hilearning.model.User; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.batch.MyBatisCursorItemReader; import org.mybatis.spring.batch.MyBatisPagingItemReader; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import java.util.List; /** * user: almo * date: 2019/7/2 **/ @Configuration public class MigrateBatchConfig { @Autowired protected JobBuilderFactory jobBuilderFactory; @Autowired protected StepBuilderFactory stepBuilderFactory; @Bean("migrateJob") public Job migrateJob(@Qualifier("migrateStep") Step step) { return jobBuilderFactory.get("migrateJob") .incrementer(new RunIdIncrementer()) .flow(step)//为Job指定Step .end() .build(); } @Bean public Step migrateStep(@Qualifier("userReader") ItemReader reader, @Qualifier("userProcessor") ItemProcessor<User, User> processor, UserBatchWriter writer) { return stepBuilderFactory .get("migrateStep") .<User, User>chunk(5)//批处理每次提交65000条数据 .reader(reader)//给step绑定reader .processor(processor)//给step绑定processor .writer(writer)//给step绑定writer .build(); } @Bean public ItemReader<User> userReader(@Qualifier("mybatis-sqlSessionFactory") SqlSessionFactory sqlSessionFactory) { BatisCursorItemReader reader = new BatisCursorItemReader(); reader.setQueryId("com.qd.almo.hilearning.dao.UserDao.selectAllUsers"); reader.setSqlSessionFactory(sqlSessionFactory); return reader; } @Bean public ItemProcessor<User, User> userProcessor() { return new ItemProcessor<User, User>() { @Override public User process(User user) throws Exception { user.setPhone("3"); System.out.println("processor thread:"+ Thread.currentThread().getName()); return user; } }; } }