体验一下SpringBatch官网的入门例子,例子比较简单,从一个csv文件中读取名字信息然后转换为大写后插入到数据库中。核心的Step操作如下:
创建一个SpringBoot项目
通过Spring向导创建一个SpringBoot项目,选中SpringBtach即可。完成的pom.xml如下:
<?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.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ycxy</groupId>
<artifactId>batchsduty01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>batchsduty01</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-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
<!--
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
官网的数据库使用嵌入式数据库hsql,不需要进行任何介质安装,非常方便。后续要时间再改造为Mysql。
业务测试和SQL语句
创建src/main/resources/sample-data.csv和src/main/resources/schema-all.sql。
Jill,Doe
Joe,Doe
Justin,Doe
Jane,Doe
John,Doe
DROP TABLE people IF EXISTS;
CREATE TABLE people (
person_id BIGINT IDENTITY NOT NULL PRIMARY KEY,
first_name VARCHAR(20),
last_name VARCHAR(20)
);
注意文件名别乱改,SpringBoot自动加载识别schema-all.sql文件。
创建业务类
package com.example.batchprocessing;
public class Person {
private String lastName;
private String firstName;
public Person() {
}
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "firstName: " + firstName + ", lastName: " + lastName;
}
}
创建一个ItemProcessor实现
package com.example.batchprocessing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemProcessor;
public class PersonItemProcessor implements ItemProcessor<Person, Person> {
private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class);
@Override
public Person process(final Person person) throws Exception {
final String firstName = person.getFirstName().toUpperCase();
final String lastName = person.getLastName().toUpperCase();
final Person transformedPerson = new Person(firstName, lastName);
log.info("Converting (" + person + ") into (" + transformedPerson + ")");
return transformedPerson;
}
}
创建一个Job并进行相关Bean配置
创建一个监听
package com.example.batchprocessing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class JobCompletionNotificationListener extends JobExecutionListenerSupport {
private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);
private final JdbcTemplate jdbcTemplate;
@Autowired
public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void afterJob(JobExecution jobExecution) {
if(jobExecution.getStatus() == BatchStatus.COMPLETED) {
log.info("!!! JOB FINISHED! Time to verify the results");
jdbcTemplate.query("SELECT first_name, last_name FROM people",
(rs, row) -> new Person(
rs.getString(1),
rs.getString(2))
).forEach(person -> log.info("Found <" + person + "> in the database."));
}
}
}
创建Job及相关的Bean配置
package com.ycxy.batchsduty01.batchprocessing;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
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.support.RunIdIncrementer;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
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;
@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Bean
public FlatFileItemReader<Person> reader() {
return new FlatFileItemReaderBuilder<Person>()
.name("personItemReader")
.resource(new ClassPathResource("sample-data.csv"))
.delimited()
.names(new String[]{"firstName", "lastName"})
.fieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
setTargetType(Person.class);
}})
.build();
}
@Bean
public PersonItemProcessor processor() {
return new PersonItemProcessor();
}
@Bean
public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
return new JdbcBatchItemWriterBuilder<Person>()
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
.dataSource(dataSource)
.build();
}
@Bean
public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
return jobBuilderFactory.get("importUserJob")
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(step1)
.end()
.build();
}
@Bean
public Step step1(JdbcBatchItemWriter<Person> writer) {
return stepBuilderFactory.get("step1")
.<Person, Person> chunk(10)
.reader(reader())
.processor(processor())
.writer(writer)
.build();
}
}
修改启动类
package com.ycxy.batchsduty01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Batchsduty01Application {
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(Batchsduty01Application.class, args)));
// SpringApplication.run(Batchsduty01Application.class, args);
}
}
运行日志:
2020-07-20 08:16:30.512 INFO 6816 --- [ main] c.y.b.Batchsduty01Application : Starting Batchsduty01Application on DESKTOP-5OBEU9N with PID 6816 (F:\yusys\cebank\demo\spbootbatch\batchsduty01\target\classes started by admin in F:\yusys\cebank\demo\spbootbatch\batchsduty01)
2020-07-20 08:16:30.514 INFO 6816 --- [ main] c.y.b.Batchsduty01Application : No active profile set, falling back to default profiles: default
2020-07-20 08:16:30.844 INFO 6816 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
2020-07-20 08:16:30.856 INFO 6816 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 10ms. Found 0 JDBC repository interfaces.
2020-07-20 08:16:31.004 INFO 6816 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-07-20 08:16:31.005 WARN 6816 --- [ main] com.zaxxer.hikari.util.DriverDataSource : Registered driver with driverClassName=org.hsqldb.jdbcDriver was not found, trying direct instantiation.
2020-07-20 08:16:31.162 INFO 6816 --- [ main] com.zaxxer.hikari.pool.PoolBase : HikariPool-1 - Driver does not support get/set network timeout for connections. (feature not supported)
2020-07-20 08:16:31.164 INFO 6816 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-07-20 08:16:31.268 INFO 6816 --- [ main] o.s.b.c.r.s.JobRepositoryFactoryBean : No database type set, using meta data indicating: HSQL
2020-07-20 08:16:31.323 INFO 6816 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
2020-07-20 08:16:31.413 INFO 6816 --- [ main] c.y.b.Batchsduty01Application : Started Batchsduty01Application in 1.135 seconds (JVM running for 3.188)
2020-07-20 08:16:31.414 INFO 6816 --- [ main] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: []
2020-07-20 08:16:31.448 INFO 6816 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=importUserJob]] launched with the following parameters: [{run.id=1}]
2020-07-20 08:16:31.472 INFO 6816 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [step1]
2020-07-20 08:16:31.490 INFO 6816 --- [ main] c.y.b.b.PersonItemProcessor : Converting (firstName: Jill, lastName: Doe) into (firstName: JILL, lastName: DOE)
2020-07-20 08:16:31.490 INFO 6816 --- [ main] c.y.b.b.PersonItemProcessor : Converting (firstName: Joe, lastName: Doe) into (firstName: JOE, lastName: DOE)
2020-07-20 08:16:31.490 INFO 6816 --- [ main] c.y.b.b.PersonItemProcessor : Converting (firstName: Justin, lastName: Doe) into (firstName: JUSTIN, lastName: DOE)
2020-07-20 08:16:31.490 INFO 6816 --- [ main] c.y.b.b.PersonItemProcessor : Converting (firstName: Jane, lastName: Doe) into (firstName: JANE, lastName: DOE)
2020-07-20 08:16:31.490 INFO 6816 --- [ main] c.y.b.b.PersonItemProcessor : Converting (firstName: John, lastName: Doe) into (firstName: JOHN, lastName: DOE)
2020-07-20 08:16:31.495 INFO 6816 --- [ main] o.s.batch.core.step.AbstractStep : Step: [step1] executed in 21ms
2020-07-20 08:16:31.497 INFO 6816 --- [ main] .y.b.b.JobCompletionNotificationListener : !!! JOB FINISHED! Time to verify the results
2020-07-20 08:16:31.498 INFO 6816 --- [ main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JILL, lastName: DOE> in the database.
2020-07-20 08:16:31.498 INFO 6816 --- [ main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JOE, lastName: DOE> in the database.
2020-07-20 08:16:31.498 INFO 6816 --- [ main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JUSTIN, lastName: DOE> in the database.
2020-07-20 08:16:31.498 INFO 6816 --- [ main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JANE, lastName: DOE> in the database.
2020-07-20 08:16:31.498 INFO 6816 --- [ main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JOHN, lastName: DOE> in the database.
2020-07-20 08:16:31.499 INFO 6816 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [FlowJob: [name=importUserJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED] in 32ms
2020-07-20 08:16:31.501 INFO 6816 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2020-07-20 08:16:31.502 INFO 6816 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Process finished with exit code 0
源网站:https://spring.io/guides/gs/batch-processing/