springbatch学习笔记
一、简介
二、项目搭建
1.创建项目
- 方式一:https://start.spring.io/ 网页创建项目导入开发工具
- 方式二:开发工具直接创建springboot项目配置batch相关依赖
注:方式一配置时,如出现找不到数据源错误,只需要在pom中配置数据源即可。如:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
2.入门例子编写
- 一个job可以创建多个step,每一个step都是一个执行步骤,需要用Bean注入进来。执行过程中只有step正常返回才会走下面的step。
- step执行有两种方式:tasklet、chunk(ItemReader、ItemProcessor、ItemWriter)
- flow:可以包含一个或多个step。
public Flow flowDemo(){
return new FlowBuilder<Flow>("flowDemo").start(step1()).next(step2()).build();
}
- split:并发执行,每个step有不同的线程来调用。
- job中可以用step也可以用flow,调用flow时,将flow中包含的step一起处理。
@Configuration
@EnableBatchProcessing
public class JobConfiguration {
//需要创建任务对象
@Autowired
private JobBuilderFactory jobBuilderFactory;
//任务执行由step决定
//创建step对象的对象
@Autowired
private StepBuilderFactory stepBuilderFactory;
//创建人物对象
@Bean
public Job helloWorldJob() {
return jobBuilderFactory.get("helloWorldJob").start(step1()).build();
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1").tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("helloworld");
return RepeatStatus.FINISHED;
}
}).build();
}
}
3.与持久化互联(采用mysql为例)
- 在application.properties中配置连接数据库
spring.datasource.username=root
spring.datasource.password=Caoxu0407@
spring.datasource.url=jdbc:mysql://localhost:3306/springbatch?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.schema=classpath:/org/springframework/batch/core/schema-mysql.sql
spring.batch.initialize-schema=always
- 再次执行任务代码,数据库会自动创建与batch相关的表存储执行结果及相关信息。(schema-mysql.sql)
4.使用决策器
- 决策器:根据判断条件决定走哪个step,相当于if功能。
- 决策器校验代码:
public class MyDecider implements JobExecutionDecider {
private int count;
@Override
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
count++;
if(count%2==0){
return new FlowExecutionStatus("even");
}else {
return new FlowExecutionStatus("odd");
}
}
}
- 调用端代码:
@Bean
public JobExecutionDecider myDecider(){
return new MyDecider();
}
@Bean
public Job deciderJob(){
return jobBuilderFactory.get("deciderJob").start(step1())
.next(myDecider())
.from(myDecider()).on("even").to(step2())
.from(myDecider()).on("odd").to(step3())
.end()
.build();
}
5.监听器
- 用来监听批处理作业的执行情况,创建监听器可以通过实现接口或使用注解。
- 调用端:
@Configuration
public class ListenerDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job listenerJob() {
return jobBuilderFactory.get("listenerJob")
.start(step1())
.listener(new MyJobListener())
.build();
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<String, String>chunk(2)//大小
.faultTolerant()//容错机制
.listener(new MyJobListener())//监听器
.reader(read())
.writer(writer())
.build();
}
@Bean
public ItemWriter<String> writer() {
return new ItemWriter<String>() {
@Override
public void write(List<? extends String> list) throws Exception {
for (String item : list) {
System.out.println(item);
}
}
};
}
@Bean
public ItemReader<String> read() {
return new ListItemReader<>(Arrays.asList("java", "spring", "mybatis"));
}
}
- 监听器端:
第一种方式:
public class MyChunkListener {
@BeforeChunk
public void beforeListener(ChunkContext context) {
System.out.println(context.getStepContext().getStepName() + "before");
}
@AfterChunk
public void afterListener(ChunkContext context) {
System.out.println(context.getStepContext().getStepName() + "after");
}
}
第二种方式:
public class MyJobListener implements JobExecutionListener {
@Override
public void beforeJob(JobExecution jobExecution) {
System.out.println(jobExecution.getJobInstance().getJobName()+"before");
}
@Override
public void afterJob(JobExecution jobExecution) {
System.out.println(jobExecution.getJobInstance().getJobName()+"after");
}
}
- 传递参数:需要使用监听器before方法给其赋值,在调用时调用即可。
6.Itemreader使用
- 业务层调用端:
@Configuration
public class ItemreaderDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job itemreaderDemoJob() {
return jobBuilderFactory.get("itemreaderDemoJob")
.start(itemreaderDemoJobStep())
.build();
}
@Bean
public Step itemreaderDemoJobStep() {
return stepBuilderFactory.get("itemreaderDemoJobStep")
.<String, String>chunk(2)
.reader(itemreaderDemoRead())
.writer(list -> {
for (String item : list) {
System.out.println(item + "...");
}
})
.build();
}
@Bean
public MyReader itemreaderDemoRead() {
List<String> data = Arrays.asList("aaa", "bbb", "ccc");
return new MyReader(data);
}
}
- MyReader端:
public class MyReader implements ItemReader<String> {
private Iterator<String> iterator;
public MyReader(List<String> list) {
this.iterator = list.iterator();
}
public String read() throws Exception, UnexpectedException {
if (iterator.hasNext()) {
return this.iterator.next();
} else {
return null;
}
}
}
7.从数据库中读取数据
- 业务层:
@Configuration
public class ItemreadeDbrDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DataSource dataSource;
@Autowired
@Qualifier("dbjdebcWriter")
private ItemWriter<? super User> dbjdebcWriter;
@Bean
public Job itemreaderDbDemoJob() {
return jobBuilderFactory.get("itemreaderDbDemoJob")
.start(itemreaderDbDemoJobStep())
.build();
}
@Bean
public Step itemreaderDbDemoJobStep() {
return stepBuilderFactory.get("itemreaderDbDemoJobStep")
.<User, User>chunk(2)
.reader(jdbcDemoRead())
.writer(dbjdebcWriter)
.build();
}
@Bean
@StepScope
public JdbcPagingItemReader<User> jdbcDemoRead() {
JdbcPagingItemReader<User> reader = new JdbcPagingItemReader();
reader.setDataSource(dataSource);
reader.setFetchSize(2);
reader.setRowMapper(new RowMapper<User>() {
//读取到的数据转换成user对象
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getInt(1));
user.setUsername(rs.getString(2));
user.setPassword(rs.getString(3));
user.setAge(rs.getInt(4));
return user;
}
});
//指定sql
MySqlPagingQueryProvider properties = new MySqlPagingQueryProvider();
properties.setSelectClause("id,username,password,age");
properties.setFromClause("from user");
//指定根据那个字段进行排序
Map<String, Order> sort = new HashMap<>(1);
sort.put("id", Order.ASCENDING);
properties.setSortKeys(sort);
reader.setQueryProvider(properties);
return reader;
}
}
- writer遍历层
@Component("dbjdebcWriter")
public class DbjdebcWriter implements ItemWriter<User> {
@Override
public void write(List<? extends User> list) throws Exception {
for (User user : list) {
System.out.println(user);
}
}
}
8.从文件中读取
- 业务层:
@Configuration
public class FileItemreaderDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DataSource dataSource;
@Autowired
@Qualifier("flatFileWriter")
private ItemWriter<? super User> flatFileWriter;
@Bean
public Job fileItemreaderDemo() {
return jobBuilderFactory.get("fileItemreaderDemo")
.start(fileItemreaderDemoStep())
.build();
}
@Bean
public Step fileItemreaderDemoStep() {
return stepBuilderFactory.get("fileItemreaderDemoStep")
.<User, User>chunk(2)
.reader(fileItemreaderDemoRead())
.writer(flatFileWriter)
.build();
}
@Bean
@StepScope
public FlatFileItemReader<User> fileItemreaderDemoRead() {
FlatFileItemReader<User> reader = new FlatFileItemReader();
reader.setResource(new ClassPathResource("user.txt"));
//跳过第一行,根据情况选择
reader.setLinesToSkip(1);
//数据解析
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
tokenizer.setNames(new String[]{"id","username","password","age"});
//把解析出来的一行映射到user对象
DefaultLineMapper<User> mapper = new DefaultLineMapper<> ();
mapper.setLineTokenizer(tokenizer);
mapper.setFieldSetMapper(new FieldSetMapper<User>() {
@Override
public User mapFieldSet(FieldSet fieldSet) throws BindException {
User user = new User();
user.setId(fieldSet.readInt("id"));
user.setUsername(fieldSet.readString("username"));
user.setPassword(fieldSet.readString("password"));
user.setAge(fieldSet.readInt("age"));
return user;
}
});
mapper.afterPropertiesSet();
reader.setLineMapper(mapper);
return reader;
}
}
- 遍历层
@Component("flatFileWriter")
public class FlatFileWriter implements ItemWriter<UserBean> {
@Override
public void write(List<? extends UserBean>list) throws Exception {
for(UserBean user:list){
System.out.println(user);
}
}
}
8.ItemWriter使用
- 业务层:
@Configuration
public class ItemWriterDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
@Qualifier("myWriter")
private ItemWriter<String> myWriter;
@Bean
public Job itemWriterDemoJob() {
return jobBuilderFactory.get("itemWriterDemoJob")
.start(itemWriterDemoStep())
.build();
}
@Bean
public Step itemWriterDemoStep() {
return stepBuilderFactory.get("itemWriterDemoStep")
.<String, String>chunk(5)
.reader(myRead())
.writer(myWriter)
.build();
}
@Bean
public ItemReader<String> myRead() {
List<String> items = new ArrayList<>();
for (int i = 0; i <= 50; i++) {
items.add("java" + i);
}
return new ListItemReader<String>(items);
}
}
- MyWriter遍历层
@Component("myWriter")
public class MyWriter implements ItemWriter<String> {
@Override
public void write(List<? extends String> list) throws Exception {
System.out.println(list.size());
for(String str:list){
System.out.println(str);
}
}
}
9.读取数据并插入数据库
- 业务层:
@Configuration
public class ItemWriterDbDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
@Qualifier("faltFileReaderConfig")
private ItemReader<User> faltFileReaderConfig;
@Autowired
@Qualifier("itemWriterDbConfig")
private ItemWriter<User> itemWriterDbConfig;
@Bean
public Job itemWriterDbDemoJob() {
return jobBuilderFactory.get("itemWriterDbDemoJob")
.start(itemWriterDbDemoStep())
.build();
}
@Bean
public Step itemWriterDbDemoStep() {
return stepBuilderFactory.get("itemWriterDbDemoStep")
.<User, User>chunk(2)
.reader(faltFileReaderConfig)
.writer(itemWriterDbConfig)
.build();
}
@Bean
public ItemReader<String> myRead() {
List<String> items = new ArrayList<>();
for (int i = 0; i <= 50; i++) {
items.add("java" + i);
}
return new ListItemReader<String>(items);
}
}
- 读文件
@Configuration
public class FaltFileReaderConfig {
@Bean
public FlatFileItemReader<User> faltFileReaderConfig() {
FlatFileItemReader<User> reader = new FlatFileItemReader();
reader.setResource(new ClassPathResource("user.txt"));
//跳过第一行,根据情况选择
//reader.setLinesToSkip(1);
//数据解析
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
tokenizer.setNames(new String[]{"id","username","password","age"});
//把解析出来的一行映射到user对象
DefaultLineMapper<com.example.springbatch.itemreaderDb.User> mapper = new DefaultLineMapper<> ();
mapper.setLineTokenizer(tokenizer);
mapper.setFieldSetMapper(new FieldSetMapper<com.example.springbatch.itemreaderDb.User>() {
@Override
public com.example.springbatch.itemreaderDb.User mapFieldSet(FieldSet fieldSet) throws BindException {
com.example.springbatch.itemreaderDb.User user = new User();
user.setId(fieldSet.readInt("id"));
user.setUsername(fieldSet.readString("username"));
user.setPassword(fieldSet.readString("password"));
user.setAge(fieldSet.readInt("age"));
return user;
}
});
mapper.afterPropertiesSet();
reader.setLineMapper(mapper);
return reader;
}
}
- 写数据库
@Configuration
public class ItemWriterDbConfig {
@Autowired
private DataSource dataSource;
@Bean
public JdbcBatchItemWriter<User> itemWriterDbConfig(){
JdbcBatchItemWriter<User> writer = new JdbcBatchItemWriter<User>();
writer.setDataSource(dataSource);
writer.setSql("inster into user (id,username,password,age) values"+
"(:id,:username:password:age)");
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<User>());
return writer;
}
}