Spring Bath是一个开源的、全面的、轻量级的批处理框架,通过Spring Batch可以实现批处理应用程序的开发;除此之外,还提供记录/跟踪、事物管理、作业处理统计、作业重启、以及资源管理等功能。Spring Batch结合定时任务可以发挥更大的作用。
下面先看简介原理,再来实战
SpringBatch 核心组件简介:
1)JobRepository:用来注册Job容器,设置数据库相关属性。
2)JobLauncher:用来启动Job的接口
3)Job:我们要实际执行的任务,包含一个或多个
4)Step:即步骤,包括:ItemReader->ItemProcessor->ItemWriter
5)ItemReader:用来读取数据,做实体类与数据字段之间的映射。比如读取csv文件中的人员数据,之后对应实体AuthUser的字段做mapper
6)ItemProcessor:用来处理数据的接口,同时可以做数据校验(设置校验器,使用JSR-303(hibernate-validator)注解)
7)ItemWriter:用来输出数据的接口,设置数据库源。编写预处理SQL插入语句
从早期的spring开发,到Spring MVC的web开发,再到现在的基于Spring Boot进行微服务开发,都具有简化开发,增强规范,快速集成等特点,而在数据处理领域,spring同样有一个开发框架,那就是Spring Batch。Spring Batch是一个轻量级,完善的批处理框架,旨在帮助企业建立健壮高效的批处理应用程序。 它是以Spring 框架为基础开发,使得原来使用Spring框架的开发者可以更容易利用原来的服务。当前新版本的Spring Batch更是可以直接基于Spring Boot进行开发,使得开发更简单、快捷。
- 丰富的开箱即用组件
开箱即用组件包括各种资源的读、写。读/写:支持文本文件读/写、XML文件读/写、数据库读/写、JMS队列读/写等。还提供作业仓库,作业调度器等基础设施,大大简化开发复杂度。- 面向chunk处理
支持多次读、一次写、避免多次对资源的写入,大幅提升批处理效率。- 事务管理能力
默认采用Spring提供的声明式事务管理模型,面向Chunk的操作支持事务管理,同时支持为每个tasklet操作设置细粒度的事务配置:隔离级别、传播行为、超时设置等。- 元数据管理
自动记录Job和Step的执行情况、包括成功、失败、失败的异常信息、执行次数、重试次数、跳过次数、执行时间等,方便后期的维护和查看。- 易监控的批处理应用
提供了灵活的监控模式,包括直接查看数据库、通过Spring Batch提供的API查看、JMX控制台查看等。其中还说到Spring Batch Admin,不过这个项目已不维护,改为用Spring Cloud Data Flow了。- 丰富的流程定义
支持顺序任务、条件分支任务、基于这两种任务可以组织复杂的任务流程。- 健壮的批处理应用
支持作业的跳过、重试、重启能力、避免因错误导致批处理作业的异常中断。- 易扩展的批处理应用
扩展机制包括多线程执行一个Step(Multithreaded step)、多线程并行执行多个Step(Parallelizing step)、远程执行作业(Remote chunking)、分区执行(partitioning step)。- 复用企业现有IT资产
提供多种Adapter能力,使得企业现有的服务可以方便集成到批处理应用中。避免重新开发、达到复用企业遗留的服务资产。
ItemReader | 说明 |
---|---|
ListItemReader | 读取List类型数据,只能读一次 |
ItemReaderAdapter | ItemReader适配器,可以复用现有的读操作 |
FlatFileItemReader | 读Flat类型文件 |
StaxEventItemReader | 读XML类型文件 |
JdbcCursorItemReader | 基于JDBC游标方式读数据库 |
HibernateCursorItemReader | 基于Hibernate游标方式读数据库 |
StoredProcedureItemReader | 基于存储过程读数据库 |
JpaPagingItemReader | 基于Jpa方式分页读数据库 |
JdbcPagingItemReader | 基于JDBC方式分页读数据库 |
HibernatePagingItemReader | 基于Hibernate方式分页读取数据库 |
JmsItemReader | 读取JMS队列 |
IteratorItemReader | 迭代方式的读组件 |
MultiResourceItemReader | 多文件读组件 |
MongoItemReader | 基于分布式文件存储的数据库 MongoDB读组件 |
Neo4jItemReader | 面向网络的数据库Neo4j的读组件 |
ResourcesItemReader | 基于批量资源的读组件,每次读取返回资源对象 AmqpItemReader读取AMQP队列组件 |
RepositoryItemReader | 基于 Spring Data的读组件 |
ItemProcessor | 说明 |
---|---|
CompositeItemProcessor | 组合处理器,可以封装多个业务处理服务 |
ItemProcessorAdapter | ItemProcessor适配器,可以复用现有的业务处理服务 |
PassThroughItemProcessor | 不做任何业务处理,直接返回读到的数据 |
ValidatingItemProcessor | 数据校验处理器,支持对数据的校验,如果校验不通过可以进行过滤掉或者通过skip的方式跳过对记录的处理 |
ItemWriter | 说明 |
---|---|
FlatFileItemWriter | 写Flat类型文件 |
MultiResourceItemWriter | 多文件写组件 |
StaxEventItemWriter | 写XML类型文件 |
AmqpItemWriter | 写AMQP类型消息 |
ClassifierCompositeItemWriter | 根据 Classifier路由不同的Item到特定的ItemWriter处理 |
HiberateItemWriter | 基于Hibernate方式写数据库 |
ItemWriterAdapter | ItemWriter适配器,可以复用现有的写服务 |
JdbcBatchItemWriter | 基于JDBC方式写数据库 |
JmsItemWriter | 写JMS队列 JpaItemWriter基于Jpa方式写数据库 |
GemfireItemWriter | 基于分布式数据库Gemfire的写组件 |
SpELMappingGemfireItemWriter | 基于Spring表达式语言写分布式数据库Gemfire的写组件 |
MimeMessageItemWriter | 发送邮件的写组件 |
MongoItemWriter | 基于分布式文件存储的数据库MongoDB写组件 |
Neo4jItemWriter | 面向网络的数据库Neo4j的读组件 |
PropertyExtractingDelegatingItemWriter | 属性抽取代理写组件:通过调用给定的 Spring Bean方法执行写入,参数由Item中指定的属性字段获取作为参数 |
RepositoryItemWriter基于 | Spring Data的写组件 |
SimpleMailMessageItemWriter | 发送邮件的写组件 |
CompositeItemWriter | 条目写的组合模式,支持组装多个ItemWriter |
整体流程:从csv文件中读数据,写入到mysql数据库,只需要使用FlatFileItemReader和JdbcBatchItemWriter即可。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yangxf</groupId>
<artifactId>demoBatch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demoBatch</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</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.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/batch_demo?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT
spring.datasource.username=root
spring.datasource.password=1234%^&*
spring.datasource.schema=classpath:/org/springframework/batch/core/schema-mysql.sql
##禁止自动执行
spring.batch.initialize-schema=always
spring.batch.job.enabled=false
package com.yangxf.demoBatch;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableBatchProcessing//开启springbatch框架功能
public class DemoBatchApplication {
public static void main(String[] args) {
SpringApplication.run(DemoBatchApplication.class, args);
}
}
/**
* FileName: ExcelBatchConfig
* Author: linwd
* Date: 2021/5/5 14:07
* Description: 批量导入数据
* History:
*
package com.yangxf.demoBatch.config;
import com.yangxf.demoBatch.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.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.sql.DataSource;
/**
* 〈一句话功能简述〉
* 〈批量导入数据〉
*
* @author linwd
* @create 2021/5/5
* @since 1.0.0
*/
@Configuration
public class ExcelBatchConfig {
@Autowired
JobBuilderFactory jobBuilderFactory;
@Autowired
StepBuilderFactory stepBuilderFactory;
@Autowired
DataSource dataSource;
@Bean
@StepScope
FlatFileItemReader <User> itemReader(){
FlatFileItemReader<User> reader=new FlatFileItemReader<>();
reader.setLinesToSkip(1);
reader.setEncoding("UTF-8");//设置文件编码格式,csv默认编码格式为ANSI,demoexcel保存后,需要用文本文档打开,然后另存为时,将默认的编码格式调整为UTF-8,否则保存到数据库中的中文乱码
reader.setResource(new ClassPathResource("demo.csv"));
reader.setLineMapper(new DefaultLineMapper<User>(){{
setLineTokenizer(new DelimitedLineTokenizer(){{
setNames("id","username","sex","addr");
setDelimiter(",");
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<User>(){{
setTargetType(User.class);
}});
}});
return reader;
}
@Bean
JdbcBatchItemWriter jdbcBatchItemWriter(){
JdbcBatchItemWriter writer=new JdbcBatchItemWriter();
writer.setDataSource(dataSource);
writer.setSql("insert into t_user (id,username,sex,addr) values (:id,:username,:sex,:addr)");
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());
return writer;
}
@Bean
Step excleStep(){
return stepBuilderFactory.get("excleStep")
.<User,User>chunk(5000)
.reader(itemReader())
.writer(jdbcBatchItemWriter())
.build();
}
@Bean
Job excelJob(){
return jobBuilderFactory.get("excelJob")
.start(excleStep())
.build();
}
}
/**
* FileName: Entity
* Author: linwd
* Date: 2021/5/5 14:10
* Description:
* History:
*
package com.yangxf.demoBatch.entity;
/**
* 〈一句话功能简述〉
* 〈〉
*
* @author linwd
* @create 2021/5/5
* @since 1.0.0
*/
public class User {
private Integer id;
private String username;
private String sex;
private String addr;
public User() {
}
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;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
package com.yangxf.demoBatch;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoBatchApplicationTests {
@Autowired
JobLauncher jobLauncher;
@Autowired
Job job;
@Test
void bathcTest() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
jobLauncher.run(job,new JobParametersBuilder().toJobParameters());
}
}
生成业务表数据。
1、不支持excel格式,默认支持csv格式。
2、csv文件默认编码格式为ANSI,需要调整为UTF-8。
3 、执行sql注意不要写错。