写在最前
1、为方便开发,本程序所用框架为springboot+mybatis,同时mybatis还集成了 generator 插件;如果对这些开发环境不熟悉,建议先查询相关资料,搭建springboot+mybatis环境,再集成spring batch。
2、在配置job、step等spring batch 的bean时,用的是java config方式,如想用xml方式配置,可参考 之前的博客:https://blog.csdn.net/Chris___/article/details/103166094
3、源代码github: https://github.com/Horven-Jane/springBatchDemo1,可用于快速验证。
------------------------------------------------------------------------------------------------------------------------------------------------
Job Repository 用来存储Job执行期的元数据,这里的元数据是指Job Instance、Job Execution、Job Parameters、StepExecution、Execution Context等数据。
有关元数据的介绍,这里暂不做详细介绍,读者暂时可以将它们理解为spring batch运行时产生的一些中间数据。
有两种Job Repository 的实现方式,一种是存放在内存中,这在之前的博客中介绍了(https://blog.csdn.net/Chris___/article/details/103166094);另一种则是将元数据存放在数据库中。
本篇文章介绍第二种方式——DB Job Repository。
将元数据存放在数据库的好处:可以随时监控批处理Job的执行状态,查看Job执行结果是成功还是失败,并且使得在job失败的情况下重启Job成为可能。
以下是详细步骤。
一、初始化数据库
初始化数据库,是指要建立相应的数据库表,以便存放元数据。spring batch已经提供了相应的建表、销表语句。
在包spring-batch-core jar包下的 org.springframework.batch.core 目录中,可以找到相应的sql文件,如下:
本示例所用的数据库是Mysql,因此执行 schema-mysql.sql 中的语句,即可完成初始化。
如果想销表,则执行 schema-drop-mysql.sql。
初始化数据库后,可以看到有9张元数据表:
表对应的描述如下:
二、搭建springboot+mybatis 环境
本项目采用springboot+mybatsi作为框架,并用了mybatis的generator功能。
项目的业务场景是:从文件中读取出用户的信用卡消费账单,简单处理后(因为是示例,所以这里的处理只是打印出一句话),将这些账单写入数据库。
项目的整体结构如下:
关于springboot+mybatis的集成,这里不多介绍,可以查看博客:https://blog.csdn.net/iku5200/article/details/82856621
以下是详细步骤。
1、建立一个maven工程,引入springboot、mybatis 以及 spring batch的相关包,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>com.maple</groupId>
<artifactId>springBatchStudy02</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring boot 整合 spring batch 的jar包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- mybatis generator 自动生成代码插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>${basedir}\src\main\resources\generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、接着配置数据库连接,编写application.properties以及application-dev.properties文件。
application.properties 中只有一句话:
spring.profiles.active=dev
表示当前环境是dev。
application-dev.properties 内容如下:
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/spring_batch?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
mybatis.mapper-locations=classpath:mapping/*.xml
#全局的映射,不用在xml文件写实体类的全路径
mybatis.type-aliases-package=com.maple.model
#开启驼峰映射
mybatis.configuration.map-underscore-to-camel-case=true
所用的数据源是Druid。
3、编写业务代码
编写业务实体类CreditBill,该类有5个字段,如下:
public class CreditBill implements Serializable {
private String accountId;
private String name;
private Double txnAmount;
private String txnDate;
private String address;
}
利用mybatis的 generator 生成相应的Mapper 文件,以方便操作数据库。
4、配置作业(Java Config 方式 )
用Java Config 来配置 Job 以及Step。这是本文的重点。文件BatchConfig02.java内容如下:
@Configuration
@EnableBatchProcessing
public class BatchConfig02 {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public FlatFileItemReader<CreditBill> flatFileItemReader(){
FlatFileItemReader<CreditBill> reader = new FlatFileItemReader<>();
Resource resource = new FileSystemResource("src\\main\\resources\\data\\ch02\\credit_bill_info_02.txt");
reader.setResource(resource);
BeanWrapperFieldSetMapper fieldSetMapper = new BeanWrapperFieldSetMapper();
fieldSetMapper.setTargetType(CreditBill.class);
DefaultLineMapper<CreditBill> lineMapper = new DefaultLineMapper<>();
lineMapper.setFieldSetMapper(fieldSetMapper);
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
tokenizer.setDelimiter(",");
tokenizer.setNames("accountId", "name", "txnAmount", "txnDate", "address");
lineMapper.setLineTokenizer(tokenizer);
reader.setLineMapper(lineMapper);
return reader;
}
@Bean
public CreditBillProcess02 creditBillProcess02(){
return new CreditBillProcess02();
}
@Bean
public ItemWriter<CreditBill> creditBillDBWritter02(){
return new CreditBillDBWritter02();
}
/**
* 将 creditBill 写入数据库
* @return
*/
@Bean
public Job creditBillPersistJob(){
return jobBuilderFactory.get("creditBillPersistJob")
.start(creditBillPersistStep())
.build();
}
@Bean
public Step creditBillPersistStep(){
return stepBuilderFactory.get("creditBillPersistStep")
.<CreditBill, CreditBill>chunk(2)
.reader(flatFileItemReader())
.processor(creditBillProcess02())
.writer(creditBillDBWritter02())
.build();
}
}
注意:
1、需要加上 @EnableBatchProcessing 注解,这个注解的解析,见博客:https://blog.csdn.net/Chris___/article/details/103352103 ;
2、作业 job 和步骤 step 的名字,是在方法名中定义的;
3、CreditBillProcess02 只是简单地打印一句话,CreditBillDBWritter02 则把信用卡账单数据写入到mysql中。
三、运行
1、先造几个信用卡账单数据,放在credit_bill_info_02.txt 这个文件中,如下:
00000001,zhang1,3500,20190106,shenzhen
00000002,zhang2,300,20190106,shenzhen
00000003,zhang3,200,20190106,shenzhen
00000004,zhang4,500.2,20190106,shenzhen
00000005,zhang5,10,20190106,shenzhen
00000006,zhang6,600,20190106,shenzhen
2、编写一个Springboot的启动类,这个启动类上需要用上注解@SpringBootApplication
另外,如果想多次运行同一个任务(任务名相同),则需要给该任务加上不同的参数。
启动类如下:
//如果没有MapperScan这个注解,则每个mapper接口上都必须加上@Mapper 注解
@MapperScan("com.maple.dao.mapper")
@SpringBootApplication
public class Bootstrap {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Bootstrap.class, args);
JobLauncher launcher = (JobLauncher)context.getBean("jobLauncher");
Job job1 = (Job)context.getBean("creditBillPersistJob");
try{
JobParametersBuilder paramBuilder = new JobParametersBuilder();
paramBuilder.addLong("DS", System.currentTimeMillis());
JobExecution jobExecution = launcher.run(job1, paramBuilder.toJobParameters());
System.out.println("JobExecution : " + jobExecution.toString());
} catch (Exception e){
e.printStackTrace();
}
}
}
在本示例中,我给每个任务加上一个DS的参数,该参数的值是时间戳,所以可多次运行同一个任务。
3、验证结果
运行程序后,查看数据库中是否正确写入了信用卡账单的信息。
四、源代码
github : https://github.com/Horven-Jane/springBatchDemo1