Springboot之Spring Batch批处理功能实现

Springboot之Spring Batch整合

前言

Spring Bath是一个开源的、全面的、轻量级的批处理框架,通过Spring Batch可以实现批处理应用程序的开发;除此之外,还提供记录/跟踪、事物管理、作业处理统计、作业重启、以及资源管理等功能。Spring Batch结合定时任务可以发挥更大的作用。
下面先看简介原理,再来实战

一、SpringBatch 核心组件简介

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插入语句

二、SpringBatch是批处理框架

从早期的spring开发,到Spring MVC的web开发,再到现在的基于Spring Boot进行微服务开发,都具有简化开发,增强规范,快速集成等特点,而在数据处理领域,spring同样有一个开发框架,那就是Spring Batch。Spring Batch是一个轻量级,完善的批处理框架,旨在帮助企业建立健壮高效的批处理应用程序。 它是以Spring 框架为基础开发,使得原来使用Spring框架的开发者可以更容易利用原来的服务。当前新版本的Spring Batch更是可以直接基于Spring Boot进行开发,使得开发更简单、快捷。

三、SpringBatch工作原理

在这里插入图片描述

  • 一个Batch(批处理)过程由一个Job(作业)组成。这个实体封装了整个批处理过程。
  • 一个Job(作业)可以由一个或多个Step(步骤)组成。在大多数情况下,一个步骤将读取数据(通过ItemReader),处理数据(使用ItemProcessor),然后写入数据(通过ItemWriter)。
  • JobLauncher处理启动一个Job(作业)。
  • 最后,JobRepository存储关于配置和执行的Job(作业)的元数据。

四、SpringBatch优势

  • 丰富的开箱即用组件
    开箱即用组件包括各种资源的读、写。读/写:支持文本文件读/写、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能力,使得企业现有的服务可以方便集成到批处理应用中。避免重新开发、达到复用企业遗留的服务资产。

五、Spring Batch提供的读-处理-写组件简介

  • ItemReader
ItemReader说明
ListItemReader读取List类型数据,只能读一次
ItemReaderAdapterItemReader适配器,可以复用现有的读操作
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
ItemProcessor说明
CompositeItemProcessor组合处理器,可以封装多个业务处理服务
ItemProcessorAdapterItemProcessor适配器,可以复用现有的业务处理服务
PassThroughItemProcessor不做任何业务处理,直接返回读到的数据
ValidatingItemProcessor数据校验处理器,支持对数据的校验,如果校验不通过可以进行过滤掉或者通过skip的方式跳过对记录的处理
  • ItemWriter
ItemWriter说明
FlatFileItemWriter写Flat类型文件
MultiResourceItemWriter多文件写组件
StaxEventItemWriter写XML类型文件
AmqpItemWriter写AMQP类型消息
ClassifierCompositeItemWriter根据 Classifier路由不同的Item到特定的ItemWriter处理
HiberateItemWriter基于Hibernate方式写数据库
ItemWriterAdapterItemWriter适配器,可以复用现有的写服务
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

六、Spring Batch开发实战

整体流程:从csv文件中读数据,写入到mysql数据库,只需要使用FlatFileItemReader和JdbcBatchItemWriter即可。

1、创建项目,添加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 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>

2、添加application配置

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

3、开启springBatch功能

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);
	}

}

4、配置config

/**
 * FileName: ExcelBatchConfig
 * Author:   linwd
 * Date:     2021/5/5 14:07
 * Description: 批量导入数据
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
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;

/**
 * 〈一句话功能简述〉<br> 
 * 〈批量导入数据〉
 *
 * @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();
    }

}

5、映射实体

/**
 * FileName: Entity
 * Author:   linwd
 * Date:     2021/5/5 14:10
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.yangxf.demoBatch.entity;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @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;
    }
}

6、测试demo.csv放在资源目录下

在这里插入图片描述

7、添加测试单元模块

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());
	}

}

8、启动服务,生成批处理的表

在这里插入图片描述

9、test单元模块测试

生成业务表数据。

10、注意点

1、不支持excel格式,默认支持csv格式。
2、csv文件默认编码格式为ANSI,需要调整为UTF-8。
3 、执行sql注意不要写错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwd2307997664

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值