文章目录
简介
Spring Batch是个轻量级的、 完善的批处理框架,旨在帮助企业建立健壮、高效的批处理应用。Spring Batch是Spring的一个子项目,使用Java语言并基于Spring框架为基础开发,使得已经使用Spring框架的开发者或者企业更容易访问和利用企业服务。
Spring Batch提供了大量可重用的组件,包括了日志追踪、事务、任务作业统计、任务重启、跳过、重复资源管理。对于大数据量和高性能的批处理任务,Spring Batch同样提供了高级功能和特性来支持比如分区功能、远程功能。总之,通过Spring Batch能够支持简单的、复杂的和大数据量的批处理作业。
框架主要有以下功能:
- Transaction management (事务管理)
- Chunk based processing (基于块的处理)
- Declarative 1/0 (声明式的输入输出)
- Start/Stop/Restart (启动/停止/再启动)
- Retry/Skip (重试/跳过)
框架一共有4个主要角色:
- JobLauncher是任务启动器,通过它来启动任务,可以看做是程序的入口。
- Job代表着一个具体的任务。
- Step代表着一个具体的步骤,一个Job可以包含多个Step (想象把大象放进冰箱这个任务需要多少个步骤你就明白了) .
- ** JobRepository**是存储数据的地方,可以看做是一个数据库的接口,在任务执行的时候需要通过它来记录任务状态等等信息。
POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SPRING_BATCH</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.6.3</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
</project>
application.yaml
server:
port: 9999
spring:
datasource:
url: jdbc:mysql://localhost:3306/batch
password: 123456
username: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
batch:
jdbc:
initialize-schema: always
sql:
init:
schema-locations: classpath:/org/springframework/batch/core/schema-mysql.sql
作业流
Job的创建
package com.zsl.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author m1767
*/
@Configuration
@EnableBatchProcessing
@SuppressWarnings("ALL")
public class JobConfiguration {
// 注入创建 Job 对象的对象
@Autowired
private JobBuilderFactory jobBuilderFactory;
// 注入创建 Step 对象的对象
@Autowired
private StepBuilderFactory stepBuilderFactory;
/**
* 创建任务
* @return
*/
@Bean
public Job helloWorldJob(){
return jobBuilderFactory.get("helloWorldJob")
.start(stepOne())
.build();
}
/**
* 创建执行步骤
* @return
*/
@Bean
public Step stepOne(){
return stepBuilderFactory.get("stepOne")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("helloWorld!");
return RepeatStatus.FINISHED;
}
}).build();
}
}
Flow 的创建
Flow 是step的一个集合。
package com.zsl.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.builder.FlowBuilder;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author m1767
*/
@Configuration
@EnableBatchProcessing
public class FlowConfiguration {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step step001(){
return stepBuilderFactory.get("step001")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step001");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Step step002(){
return stepBuilderFactory.get("step002")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step002");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Step step003(){
return stepBuilderFactory.get("step003")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step003");
return RepeatStatus.FINISHED;
}
}).build();
}
/**
* 创建 flow 将几个步骤放在 Flow 里
* flow 是step的一个合集
* @return flow
*/
@Bean
public Flow flow(){
return new FlowBuilder<Flow>("flow")
.start(step001())
.next(step002())
.next(step003())
.build();
}
@Bean
public Job flowJob(){
return jobBuilderFactory.get("flowJob")
.start(flow())
.end()
.build();
}
}
split 并发执行Flow
package com.zsl.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.builder.FlowBuilder;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
/**
* @author m1767
*/
@Configuration
@EnableBatchProcessing
@SuppressWarnings("all")
public class Split {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step step01(){
return stepBuilderFactory.get("step01")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step01");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Step step02(){
return stepBuilderFactory.get("step02")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step02");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Step step03(){
return stepBuilderFactory.get("step03")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step03");
return RepeatStatus.FINISHED;
}
}).build();
}
/**
* 创建 flow 将几个步骤放在 Flow 里
* flow 是step的一个合集
* @return flow
*/
@Bean
public Flow flow001(){
return new FlowBuilder<Flow>("flow001")
.start(step01())
.next(step02())
.build();
}
/**
* 创建 flow 将几个步骤放在 Flow 里
* flow 是step的一个合集
* @return flow
*/
@Bean
public Flow flow002(){
return new FlowBuilder<Flow>("flow002")
.start(step03())
.build();
}
/**
* 并发执行Flow
* @return
*/
@Bean
public Job splitJob(){
return jobBuilderFactory.get("splitJob")
.start(flow001())
.split(new SimpleAsyncTaskExecutor())
.add(flow002())
.end()
.build();
}
}
决策器的使用
package com.zsl.config;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
/**
* @author m1767
*/
@SuppressWarnings("all")
public class MyDecider implements JobExecutionDecider {
private int count;
/**
* @Description: decide 决策器,先执行odd奇数
* @Param: [jobExecution, stepExecution]
* @Return: org.springframework.batch.core.job.flow.FlowExecutionStatus
*/
@Override
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
count++;
if(count%2==0){
return new FlowExecutionStatus("even偶数");
}else {
return new FlowExecutionStatus("odd奇数");
}
}
}
package com.zsl.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author m1767
*/
@Configuration
@EnableBatchProcessing
@SuppressWarnings("all")
public class Decider {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step step1(){
return stepBuilderFactory.get("step1")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step1");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Step step2(){
return stepBuilderFactory.get("step2")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step2");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public Step step3(){
return stepBuilderFactory.get("step3")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("step3");
return RepeatStatus.FINISHED;
}
}).build();
}
@Bean
public JobExecutionDecider myDecider(){
return new MyDecider();
}
/**
* 创建使用决策器的job
* 如果为 偶数则执行step2
* 如果为 奇数则执行step3
* 为其它则 返回决策器
* @return
*/
@Bean
public Job deciderJob(){
return jobBuilderFactory.get("deciderJob")
.start(step1())
.next(myDecider())
.from(myDecider()).on("even偶数").to(step2())
.from(myDecider())
.on("odd奇数").to(step3())
.from(step3())
.on("*").to(myDecider())
.end()
.build();
}
}
job嵌套
package com.zsl.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author m1767
*/
@Configuration
@EnableBatchProcessing
public class ChildJob001 {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step childStep1(){
return stepBuilderFactory.get("childStep1")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("child One");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Job childJob1(){
return jobBuilderFactory.get("childJob1")
.start(childStep1())
.build();
}
}
package com.zsl.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author m1767
*/
@Configuration
@EnableBatchProcessing
public class ChildJob002 {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Step childStep2(){
return stepBuilderFactory.get("childStep2")
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.out.println("child Two");
return RepeatStatus.FINISHED;
}
})
.build();
}
@Bean
public Job childJob2(){
return jobBuilderFactory.get("childJob2")
.start(childStep2())
.build();
}
}
package com.zsl.config;
import org.omg.CORBA.PRIVATE_MEMBER;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.JobStepBuilder;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/**
* @author m1767
*/
@Configuration
public class ParentJob {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private Job childJob1;
@Autowired
private Job childJob2;
@Autowired
private JobLauncher launcher;
@Bean
public Job parentJobs(JobRepository repository, PlatformTransactionManager transactionManager){
return jobBuilderFactory.get("parentJobs")
.start(childJob001(repository, transactionManager))
.next(childJob002(repository, transactionManager))
.build();
}
public Step childJob001(JobRepository repository, PlatformTransactionManager transactionManager){
return new JobStepBuilder(new StepBuilder("childJob001"))
.job(childJob1)
.launcher(launcher) // 使用父job的启动器
.repository(repository) // 数据源
.transactionManager(transactionManager) // 事务管理
.build();
}
public Step childJob002(JobRepository repository, PlatformTransactionManager transactionManager){
return new JobStepBuilder(new StepBuilder("childJob002"))
.job(childJob2)
.launcher(launcher)
.repository(repository)
.transactionManager(transactionManager)
.build();
}
}
spring:
batch:
job:
names: parentJobs
监听器的使用
package com.zsl.listener;
import org.springframework.batch.core.annotation.AfterChunk;
import org.springframework.batch.core.annotation.BeforeChunk;
import org.springframework.batch.core.scope.context.ChunkContext;
/**
* @author m1767
*/
public class MyChunkListener {
@BeforeChunk
public void beforeChunk(ChunkContext context){
System.out.println(context.getStepContext().getStepName()+"before");
}
@AfterChunk
public void afterChunk(ChunkContext context){
System.out.println(context.getStepContext().getStepName()+"after");
}
}
package com.zsl.listener;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
/**
* @author m1767
*/
public class MyListener 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");
}
}
package com.zsl.config;
import com.zsl.listener.MyChunkListener;
import com.zsl.listener.MyListener;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
/**
* @author m1767
*/
@Configuration
public class ListenerDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job listenerJob(){
return jobBuilderFactory.get("listenerJob")
.start(listenerStep())
.listener(new MyListener())
.build();
}
/**
* chunk 可以进行读写数据
* @return
*/
@Bean
public Step listenerStep(){
return stepBuilderFactory.get("listenerStep")
.<String,String>chunk(2)
.faultTolerant()
.listener(new MyChunkListener())
.reader(read())
.writer(write())
.build();
}
@Bean
public ItemWriter<String> write(){
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("one","two","three"));
}
}
job参数
package com.zsl.config;
import com.zsl.listener.MyListener;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
/**
* @ClassName ParametersDemo 实现Step监听器
* @Description ParametersDemo
* @Author ZX
* @Date 2020/5/30
*/
@Configuration
@EnableBatchProcessing
public class ParametersDemo implements StepExecutionListener {
/**
* @Description: 注入创建任务对象的对象
* @Param:
* @Return:
*/
@Autowired
private JobBuilderFactory jobBuilderFactory;
/**
* @Description: //任务的执行由Step决定,注入创建Step对象的对象
* @Param:
* @Return:
*/
@Autowired
private StepBuilderFactory stepBuilderFactory;
private Map<String, JobParameter> parameters;
@Bean
public Job parameterJob() {
return jobBuilderFactory.get("parameterJob")
.start(parameterStep())
.listener(new MyListener())
.build();
}
/**
* @Description: parameterStep
* Job执行的是Step,Job使用的数据肯定是在step中使用,只需给Step传递数据。
* 使用监听,使用Step级别的监听来传递数据
* @Param: []
* @Return: org.springframework.batch.core.Step
*/
@Bean
public Step parameterStep() {
return stepBuilderFactory.get("parameterStep")
.listener(this)
.tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
//输出接收到的参数的值
System.out.println(parameters.get("info"));
return RepeatStatus.FINISHED;
}
}).build();
}
@Override
public void beforeStep(StepExecution stepExecution) {
parameters = stepExecution.getJobParameters().getParameters();
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
}
启动springboot时添加参数
数据读取与输出
ItemReader 初体验
package com.zsl.batch;
import com.zsl.listener.MyListener;
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.item.ItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.List;
/**
* @author m1767
*/
@Configuration
public class ItemReaderDemo {
@Autowired
JobBuilderFactory jobBuilderFactory;
@Autowired
StepBuilderFactory stepBuilderFactory;
@Bean
public Job itemReaderDemoJob(){
return jobBuilderFactory.get("itemReaderDemoJob")
.start(itemReaderDemoStep())
.listener(new MyListener())
.build();
}
@Bean
public Step itemReaderDemoStep(){
return stepBuilderFactory.get("itemReaderDemoStep")
.<String,String>chunk(2)
.reader(reader())
.writer(list -> {
for(String item:list){
System.out.println(item);
}
})
.build();
}
@Bean
public MyReader reader(){
List<String> data = Arrays.asList("one","two","three","four");
return new MyReader(data);
}
}
package com.zsl.batch;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import java.util.Iterator;
import java.util.List;
/**
* @author m1767
*/
public class MyReader implements ItemReader<String> {
private Iterator<String> iterator;
public MyReader(List<String> list){
this.iterator = list.iterator();
}
@Override
public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if (iterator.hasNext()){
return this.iterator.next();
}else{
return null;
}
}
}
数据库的读取与输出
package com.zsl.batch;
import com.zsl.entity.User;
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.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.Order;
import org.springframework.batch.item.database.support.MySqlPagingQueryProvider;
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.jdbc.core.RowMapper;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* @author m1767
*/
@Configuration
@SuppressWarnings("all")
public class ItemReaderDBDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DataSource dataSource;
@Autowired
@Qualifier("writer")
private ItemWriter<? super User> dbWriter;
@Bean
public Job readDBJob(){
return jobBuilderFactory.get("readDBJob")
.start(readDBStep())
.build();
}
@Bean
public Step readDBStep(){
return stepBuilderFactory.get("readDBStep")
.<User,User>chunk(2)
.reader(userReader())
.writer(dbWriter)
.build();
}
@Bean
@StepScope
public JdbcPagingItemReader<User> userReader(){
JdbcPagingItemReader<User> reader = new JdbcPagingItemReader<>();
reader.setDataSource(dataSource);
reader.setFetchSize(2);
// 把读取到的记录转换成User对象
reader.setRowMapper(new RowMapper<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));
return user;
}
});
MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider();
Map<String, Order> sort = new HashMap<>(1);
provider.setSelectClause("id,username");
provider.setFromClause("from user");
sort.put("id",Order.DESCENDING);
provider.setSortKeys(sort);
reader.setQueryProvider(provider);
return reader;
}
}
package com.zsl.batch;
import com.zsl.entity.User;
import org.springframework.batch.item.ItemWriter;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author m1767
*/
@SuppressWarnings("all")
@Component("writer")
public class ItemWriterDB implements ItemWriter<User> {
@Override
public void write(List<? extends User> list) throws Exception {
for (User user:list){
System.out.println(user.toString());
}
}
}
package com.zsl.entity;
/**
* @author m1767
*/
public class User {
private Integer id;
private String username;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
'}';
}
}
ItemProcess进行逻辑校验
package com.zsl.batch;
import com.zsl.entity.User;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;
/**
* @author m1767
*/
@Component("userNameProcess")
public class UserNameProcess implements ItemProcessor<User,User> {
@Override
public User process(User user) throws Exception {
user.setUsername(user.getUsername().toUpperCase());
return user;
}
}
package com.zsl.batch;
import com.zsl.entity.User;
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.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.Order;
import org.springframework.batch.item.database.support.MySqlPagingQueryProvider;
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.jdbc.core.RowMapper;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* @author m1767
*/
@Configuration
@SuppressWarnings("all")
public class ItemReaderDBDemo {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DataSource dataSource;
@Autowired
@Qualifier("writer")
private ItemWriter<? super User> dbWriter;
@Autowired
@Qualifier("userNameProcess")
private ItemProcessor<User,User>itemProcessor;
@Bean
public Job readDBJob1(){
return jobBuilderFactory.get("readDBJob1")
.start(readDBStep1())
.build();
}
@Bean
public Step readDBStep1(){
return stepBuilderFactory.get("readDBStep1")
.<User,User>chunk(2)
.reader(userReader())
.processor(itemProcessor)
.writer(dbWriter)
.build();
}
@Bean
@StepScope
public JdbcPagingItemReader<User> userReader(){
JdbcPagingItemReader<User> reader = new JdbcPagingItemReader<>();
reader.setDataSource(dataSource);
reader.setFetchSize(2);
// 把读取到的记录转换成User对象
reader.setRowMapper(new RowMapper<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));
return user;
}
});
MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider();
Map<String, Order> sort = new HashMap<>(1);
provider.setSelectClause("id,username");
provider.setFromClause("from user");
sort.put("id",Order.DESCENDING);
provider.setSortKeys(sort);
reader.setQueryProvider(provider);
return reader;
}
}