决战数据库-spring batch(4)数据库到数据库

决战数据库-spring batch(4)数据库到数据库

tags:springbatch


1.引言

上一篇文章《快速使用组件-spring batch(3)读文件数据到数据库》Spring Batch的读、处理、写组件进行了介绍,并且以实际案例使用了FlatFileItemReader读文本文件,并把每行数据映射为实体,然后使用JdbcBatchItemWriter把实体对象数据存储到MySQL中。但在数据集成的实际应用中,更多的工作是从A数据库到B数据库,数据库之间是异构的,数据与数据的字段定义是不尽相同的,因此,在数据同步、数据抽取时,需要从源数据库读取数据,经过校验、转换,过滤、清洗,然后把数据再写到目标数据库。本文将在上一篇的基础上,实现数据库到数据库的数据同步。简单来说,只需要把从文件读数据改为从数据库读即可。可下载完整示例工程代码参考

数据库到数据库

2.开发环境

  • JDK: jdk1.8
  • Spring Boot: 2.1.4.RELEASE
  • Spring Batch:4.1.2.RELEASE
  • 开发IDE: IDEA
  • 构建工具Maven: 3.3.9
  • 日志组件logback:1.2.3
  • lombok:1.18.6

3.开发流程

上一篇文章中,已经把User数据存储在mytest数据库中,本文将以mytest数据库中的test_user表为源数据,使用Spring Batch把数据同步到目标数据库my_test1,实现MySQLMySQL的同步。注,若是不同的数据库,在配置多数据源时可更改数据库驱动和连接信息即可。关键代码如下所示:

关键代码

3.1 创建目标数据库

MySQL中创建my_test1数据库作为目标数据库,执行示例工程中的sql/my_test1.sql创建用户表,为简单起见,目标数据表与源数据表数据表结构一样。创建后如下:

目标数据库

3.2 配置多数据源

至此,我们的程序涉及三个数据库,分别是:

  • 用于Spring Batch数据存储的my_spring_batch
  • 源数据库mytest
  • 目标数据库my_test1

因此,需要先配置多数据源,配置方法跟之前一样,配置properties文件的数据库连接信息和使用注解进行配置即可。如下:

application.properties

# spring batch db
spring.datasource.jdbc-url=jdbc:mysql://localhost:3310/my_spring_batch?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=111111
# origin db
spring.origin-datasource.jdbc-url=jdbc:mysql://localhost:3310/mytest?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.origin-datasource.username=root
spring.origin-datasource.password=111111
# target db
spring.target-datasource.jdbc-url=jdbc:mysql://localhost:3310/my_test1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.target-datasource.username=root
spring.target-datasource.password=111111

然后使用注解注入多数据源,如下:

DataSourceConfig.java

@Bean("datasource")
@ConfigurationProperties(prefix="spring.datasource")
@Primary
public DataSource batchDatasource() {
    return DataSourceBuilder.create().build();
}

@Bean("originDatasource")
@ConfigurationProperties(prefix="spring.origin-datasource")
public DataSource originDatasource() {
    return DataSourceBuilder.create().build();
}

@Bean("targetDatasource")
@ConfigurationProperties(prefix="spring.target-datasource")
public DataSource targetDatasource() {
    return DataSourceBuilder.create().build();
}

3.3 添加读数据组件JdbcCursorItemReader

从数据库中读取数据,Spring Batch提供了组件JdbcCursorItemReader,通过它,可以把数据库的数据读取出来,然后映射为实体User,以供后续开发。创建方法如下:

@Bean
public ItemReader db2DbItemReader(@Qualifier("originDatasource") DataSource originDatasource) {
    String readSql = " select * from test_user";
    return new JdbcCursorItemReaderBuilder<User>()
            .dataSource(originDatasource).sql(readSql)
            .verifyCursorPosition(false).rowMapper(new UserRowMapper())
            .build();
}

说明:

  • 使用@Qualifier("originDatasource")标识源数据库
  • JdbcCursorItemReaderBuilder用于构建JdbcCursorItemReader
  • 读数据的sql语句根据实际情况编写即可,此处是读取整个表数据。
  • 需要把数据库映射为实体User,使用UserRowMapper,此mapper实现RowMapper接口,把从数据库读取的ResultSet映射为User的字段。

3.4 自定义处理组件Db2DbItemProcessor

读取到数据后,当前的处理是针对title字段,不为null的则转为大写即可。如下:

if(Objects.nonNull(title)){
    user.setTitle(title.toUpperCase());
}

3.5 添加写数据组件JdbcBatchItemWriter

写入数据,同样使用JdbcBatchItemWriter组合,编写插入sql语句,把实体User数据插入到数据库即可,如下:

@Bean
public ItemWriter db2DbWriter(@Qualifier("targetDatasource") DataSource targetDatasource) {
    String inserSql ="INSERT INTO test_user(id,name,phone,title,email,gender,date_of_birth,sys_create_time,sys_create_user,sys_update_time,sys_update_user) " +
            "VALUES (:id,:name,:phone,:title,:email,:gender,:dateOfBirth,:sysCreateTime,:sysCreateUser,:sysUpdateTime,:sysUpdateUser)";
    return new JdbcBatchItemWriterBuilder<User>()
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
            .sql(inserSql)
            .dataSource(targetDatasource)
            .build();
}

说明:

  • 使用JdbcBatchItemWriterBuilder进行JdbcBatchItemWriter的创建,设置插入数据库的sql语句,同时指定数据源即可。
  • @Qualifier("targetDatasource") DataSource datasource用于指定数据源
  • 使用BeanPropertyItemSqlParameterSourceProvider可以直接把读取的数据实体的属性数据作为参数填充到sql语句中,从而实现数据插入操作。

3.6 组装完整任务

经过上面的操作,可以使用一个java配置,把读、写、处理组装成完整的stepjob,如下所示(详细可见示例工程文件):

@Bean
public Job db2DbJob(Step db2DbStep,JobExecutionListener db2DbListener){
    String funcName = Thread.currentThread().getStackTrace()[1].getMethodName();
    return jobBuilderFactory.get(funcName)
            .listener(db2DbListener)
            .flow(db2DbStep)
            .end().build();
}
@Bean
public Step db2DbStep(ItemReader db2DbItemReader ,ItemProcessor db2DbProcessor
        ,ItemWriter db2DbWriter){
    String funcName = Thread.currentThread().getStackTrace()[1].getMethodName();
    return stepBuilderFactory.get(funcName)
            .<User,User>chunk(10)
            .reader(db2DbItemReader)
            .processor(db2DbProcessor)
            .writer(db2DbWriter)
            .build();
}

3.7 测试

参考上一文章的File2DbJobTest,编写Db2DbJobTest文件即可。如下:

@Test
public void testDb2DbJob() throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
    //构建job参数
    JobParameters jobParameters = JobUtil.makeJobParameters();
    //运行job
    Map<String, Object> stringObjectMap = jobLauncherService.startJob(db2DbJob, jobParameters);
    //测试结果
    Assert.assertEquals(ExitStatus.COMPLETED,stringObjectMap.get(SyncConstants.STR_RETURN_EXITSTATUS));
}

经过此测试,可查看到源数据库mytest中的test_user表中的数据,已全部同步到目标库my_test1中的test_user中。完成数据库到数据库的数据同步。

4.总结

本文通过简单的示例,从源数据库中读取表数据,经过处理,写入到目标数据库,具体一定的通用性。希望让大家更深入的了解Spring Batch,并能用到实践中。

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Spring Batch 的作用是实现批处理任务,其中涉及到对数据库的读写操作。因此,在使用 Spring Batch 时,需要先创建相应的数据库表来存储批处理任务的信息。以下是 Spring Batch数据库脚本: ``` CREATE TABLE BATCH_JOB_INSTANCE ( JOB_INSTANCE_ID BIGINT NOT NULL PRIMARY KEY , VERSION BIGINT, JOB_NAME VARCHAR(100) NOT NULL, JOB_KEY VARCHAR(32) NOT NULL, constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY) ) ; CREATE TABLE BATCH_JOB_EXECUTION ( JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY , VERSION BIGINT NOT NULL, JOB_INSTANCE_ID BIGINT NOT NULL, CREATE_TIME TIMESTAMP NOT NULL, START_TIME TIMESTAMP DEFAULT NULL , END_TIME TIMESTAMP DEFAULT NULL , STATUS VARCHAR(10) , EXIT_CODE VARCHAR(2500) , EXIT_MESSAGE VARCHAR(2500) , LAST_UPDATED TIMESTAMP NOT NULL, JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL, constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID) references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID) ) ; CREATE TABLE BATCH_STEP_EXECUTION ( STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY , VERSION BIGINT NOT NULL, STEP_NAME VARCHAR(100) NOT NULL, JOB_EXECUTION_ID BIGINT NOT NULL, START_TIME TIMESTAMP NOT NULL , END_TIME TIMESTAMP DEFAULT NULL , STATUS VARCHAR(10) , COMMIT_COUNT BIGINT , READ_COUNT BIGINT , FILTER_COUNT BIGINT , WRITE_COUNT BIGINT , READ_SKIP_COUNT BIGINT , WRITE_SKIP_COUNT BIGINT , PROCESS_SKIP_COUNT BIGINT , ROLLBACK_COUNT BIGINT , EXIT_CODE VARCHAR(2500) , EXIT_MESSAGE VARCHAR(2500) , LAST_UPDATED TIMESTAMP NOT NULL, constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID) references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) ) ; CREATE TABLE BATCH_JOB_EXECUTION_PARAMS ( JOB_EXECUTION_ID BIGINT NOT NULL , TYPE_CD VARCHAR(6) NOT NULL , KEY_NAME VARCHAR(100) NOT NULL , STRING_VAL VARCHAR(250) , DATE_VAL TIMESTAMP DEFAULT NULL , LONG_VAL BIGINT , DOUBLE_VAL DOUBLE PRECISION , IDENTIFYING CHAR(1) NOT NULL , constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID) references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) ) ; CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT ( STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, SHORT_CONTEXT VARCHAR(2500) NOT NULL, SERIALIZED_CONTEXT TEXT , constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID) references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID) ) ; CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT ( JOB_EXECUTION_ID PRIMARY KEY, SHORT_CONTEXT VARCHAR(2500) NOT NULL, SERIALIZED_CONTEXT TEXT , constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID) references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) ) ; CREATE TABLE BATCH_STEP_EXECUTION_SEQ ( ID BIGINT NOT NULL, constraint STEP_EXECUTION_SEQ_PK primary key (ID) ) ; INSERT INTO BATCH_STEP_EXECUTION_SEQ values(0); CREATE TABLE BATCH_JOB_SEQ ( ID BIGINT NOT NULL, constraint JOB_SEQ_PK primary key (ID) ) ; INSERT INTO BATCH_JOB_SEQ values(0); CREATE TABLE BATCH_JOB_EXECUTION_SEQ ( ID BIGINT NOT NULL, constraint JOB_EXECUTION_SEQ_PK primary key (ID) ) ; INSERT INTO BATCH_JOB_EXECUTION_SEQ values(0); CREATE TABLE BATCH_JOB_PARAMS ( JOB_INSTANCE_ID BIGINT NOT NULL , TYPE_CD VARCHAR(6) NOT NULL , KEY_NAME VARCHAR(100) NOT NULL , STRING_VAL VARCHAR(250) , DATE_VAL TIMESTAMP DEFAULT NULL , LONG_VAL BIGINT , DOUBLE_VAL DOUBLE PRECISION , IDENTIFYING CHAR(1) NOT NULL , constraint JOB_INST_PARAMS_FK foreign key (JOB_INSTANCE_ID) references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID) ) ; ``` 这些脚本将创建 Spring Batch 中使用的所有表。在使用 Spring Batch 进行开发时,可以将这些脚本直接在数据库中执行,以创建相应的表。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值