Skip to main content
 首页 » 编程设计

Spring Batch 写数据库教程

2022年07月19日131youxin

Spring Batch 写数据库教程

上文我们学习如何读数据库,本文我们看如何通过Spring Batch写数据库。

1.需求及环境准备

1.1. 示例需求说明

需要实现把在线学习系统中的学生信息通过Srping job写入数据库,单个学生信息类如下:学生姓名、电子邮件、已购学习包。写数据库之前,我们需要提供输入数据组件。本例我们使用StudentDto对象,其包括单个学生信息:

@Data 
public class StudentDTO { 
  
    private String emailAddress; 
    private String name; 
    private String purchasedPackage; 
} 

下面开始配置应用上下文。

1.2. 配置应用上下文

在配置写数据库ItemWriter对象之前,需要先配置ItemWriter bean,有两种方式:

1)、如果使用Spring Framework,需要下列几个步骤:

  • 在应用上下文配置类中增加jdbcTemplate() 方法.

  • 确保jdbcTemplate() 方法返回 NamedParameterJdbcTemplate 对象并带有DataSource对象作为参数.

  • 在方法上增加@Bean 注解.

  • 实现方法并返回NamedParameterJdbcTemplate 对象.

部分对面如下:

import com.zaxxer.hikari.HikariConfig; 
import com.zaxxer.hikari.HikariDataSource; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.env.Environment; 
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 
  
import javax.sql.DataSource; 
import java.util.Properties; 
  
@Configuration 
public class PersistenceContext { 
  
    @Bean(destroyMethod = "close") 
    DataSource dataSource(Environment env) { 
        HikariConfig dataSourceConfig = new HikariConfig(); 
  
        dataSourceConfig.setDriverClassName(env.getRequiredProperty("db.driver")); 
        dataSourceConfig.setJdbcUrl(env.getRequiredProperty("db.url")); 
        dataSourceConfig.setUsername(env.getRequiredProperty("db.username")); 
        dataSourceConfig.setPassword(env.getRequiredProperty("db.password")); 
  
        return new HikariDataSource(dataSourceConfig); 
    } 
      
    @Bean 
    NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) { 
        return new NamedParameterJdbcTemplate(dataSource); 
    } 
} 

2)、如果使用Spring Boot,而且还没有禁用它的自动配置特性,那么我们就不必对配置进行任何更改,因为Spring Boot同时配置了JdbcTemplate和NamedParameterJdbcTemplate bean。

下面继续配置ItemWriter,负责写信息入库。

2. 通过jdbc写数据库

通过下面几个步骤配置ItemWriter:

第一步创建配置类,其中包括Spring job流程描述。创建CsvFileToDatabaseJobConfig 类并增加注解 @Configuration。对应代码如下:

import org.springframework.context.annotation.Configuration; 
  
@Configuration 
public class CsvFileToDatabaseJobConfig { 
  
} 

第二步创建方法配置ItemWriter bean,通过下面几步实现:

  • 在配置类中增加方法,确保方法返回ItemWriter 对象.

  • 确保方法带有 DataSource 和 NamedParameterJdbcTemplate 对象作为参数.

  • 暂时通过返回null实现方法.

增加方法后CsvFileToDatabaseJobConfig类代码如下:

import org.springframework.batch.item.ItemWriter; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 
  
import javax.sql.DataSource; 
  
@Configuration 
public class CsvFileToDatabaseJobConfig { 
      
    @Bean 
    ItemWriter<StudentDTO> csvFileDatabaseItemWriter(DataSource dataSource,  
                                                     NamedParameterJdbcTemplate jdbcTemplate) { 
        return null; 
    } 
} 

第三步创建JdbcBatchItemWriter对象,设置数据源和jdbcTemplate,确保方法返回该对象。最终CsvFileToDatabaseJobConfig类csvFileDatabaseItemWriter方法的完整代码如下:

import org.springframework.batch.item.ItemWriter; 
import org.springframework.batch.item.database.JdbcBatchItemWriter; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 
  
import javax.sql.DataSource; 
  
@Configuration 
public class CsvFileToDatabaseJobConfig { 
  
    @Bean 
    ItemWriter<StudentDTO> csvFileDatabaseItemWriter(DataSource dataSource,  
                                                     NamedParameterJdbcTemplate jdbcTemplate) { 
        JdbcBatchItemWriter<StudentDTO> databaseItemWriter = new JdbcBatchItemWriter<>(); 
        databaseItemWriter.setDataSource(dataSource); 
        databaseItemWriter.setJdbcTemplate(jdbcTemplate); 
          
        return databaseItemWriter; 
    } 
} 

下面配置插入数据库的INSERT语句。可以使用两者策略制定INSERT语句的参数,两者配置有差异。下面首先看看索引参数。

2.1. 索引参数

索引参数配置包括下面几步:

第一步创建出入student表的INSERT语句,使用常量属性保存INSERT语句并确保JdbcBatchItemWriter 对象使用该常量,CsvFileToDatabaseJobConfig代码如下:

import org.springframework.batch.item.ItemWriter; 
import org.springframework.batch.item.database.JdbcBatchItemWriter; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 
  
import javax.sql.DataSource; 
  
@Configuration 
public class CsvFileToDatabaseJobConfig { 
  
    private static final String QUERY_INSERT_STUDENT = "INSERT " + 
            "INTO students(email_address, name, purchased_package) " + 
            "VALUES (?, ?, ?)"; 
  
    @Bean 
    ItemWriter<StudentDTO> csvFileDatabaseItemWriter(DataSource dataSource, 
                                                     NamedParameterJdbcTemplate jdbcTemplate) { 
        JdbcBatchItemWriter<StudentDTO> databaseItemWriter = new JdbcBatchItemWriter<>(); 
        databaseItemWriter.setDataSource(dataSource); 
        databaseItemWriter.setJdbcTemplate(jdbcTemplate); 
  
        databaseItemWriter.setSql(QUERY_INSERT_STUDENT); 
  
        return databaseItemWriter; 
    } 
} 

第二步创建实现 ItemPreparedStatementSetter接口的类,该类负责给PreparedStatement 对象设置实际参数值,通过实现setValues方法实现。主要包括下面两步:

  • 创建实现ItemPreparedStatementSetter接口的类,并设置T类型为StudentDTO。
  • 实现setValues方法并按顺序配置参数值: emailAddress, name, purchasedPackage.

完整代码如下:

import org.springframework.batch.item.database.ItemPreparedStatementSetter; 
  
import java.sql.PreparedStatement; 
import java.sql.SQLException; 
  
final class StudentPreparedStatementSetter implements ItemPreparedStatementSetter<StudentDTO> { 
  
    @Override 
    public void setValues(StudentDTO student,  
                          PreparedStatement preparedStatement) throws SQLException { 
        preparedStatement.setString(1, student.getEmailAddress()); 
        preparedStatement.setString(2, student.getName()); 
        preparedStatement.setString(3, student.getPurchasedPackage()); 
    } 
} 

第三步确保JdbcBatchItemWriter 使用StudentPreparedStatementSetter。确保在执行INSERT语句时实际参数值被正确设置。
正确配置ItemPreparedStatementSetter 对象后,配置类的CsvFileToDatabaseJobConfig代码如下:

import org.springframework.batch.item.ItemWriter; 
import org.springframework.batch.item.database.ItemPreparedStatementSetter; 
import org.springframework.batch.item.database.JdbcBatchItemWriter; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 
  
import javax.sql.DataSource; 
  
@Configuration 
public class CsvFileToDatabaseJobConfig { 
  
    private static final String QUERY_INSERT_STUDENT = "INSERT " + 
            "INTO students(email_address, name, purchased_package) " + 
            "VALUES (?, ?, ?)"; 
  
    @Bean 
    ItemWriter<StudentDTO> csvFileDatabaseItemWriter(DataSource dataSource, 
                                                     NamedParameterJdbcTemplate jdbcTemplate) { 
        JdbcBatchItemWriter<StudentDTO> databaseItemWriter = new JdbcBatchItemWriter<>(); 
        databaseItemWriter.setDataSource(dataSource); 
        databaseItemWriter.setJdbcTemplate(jdbcTemplate); 
  
        databaseItemWriter.setSql(QUERY_INSERT_STUDENT); 
  
        ItemPreparedStatementSetter<StudentDTO> valueSetter =  
                new StudentPreparedStatementSetter(); 
        databaseItemWriter.setItemPreparedStatementSetter(valueSetter); 
  
        return databaseItemWriter; 
    } 
} 

通过上面几步就完成了ItemWriter 的配置,通过INSERT语句和索引参数实现在数据库中插入信息。

2.2. 命名参数

使用命名需要下面几个步骤进行配置:

第一步使用命名参数创建插入表的INSERT语句。使用命名参数的名称应该和StudentDto类属性名称保持一致。然后定义常量保存INSERT语句并确保JdbcBatchItemWriter 使用该常量,请看CsvFileToDatabaseJobConfig配置代码:

import org.springframework.batch.item.ItemWriter; 
import org.springframework.batch.item.database.JdbcBatchItemWriter; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 
  
import javax.sql.DataSource; 
  
@Configuration 
public class CsvFileToDatabaseJobConfig { 
      
    private static final String QUERY_INSERT_STUDENT = "INSERT " + 
            "INTO students(email_address, name, purchased_package) " + 
            "VALUES (:emailAddress, :name, :purchasedPackage)"; 
      
    @Bean 
    ItemWriter<StudentDTO> csvFileDatabaseItemWriter(DataSource dataSource,  
                                                     NamedParameterJdbcTemplate jdbcTemplate) { 
        JdbcBatchItemWriter<StudentDTO> databaseItemWriter = new JdbcBatchItemWriter<>(); 
        databaseItemWriter.setDataSource(dataSource); 
        databaseItemWriter.setJdbcTemplate(jdbcTemplate); 
  
        databaseItemWriter.setSql(QUERY_INSERT_STUDENT); 
  
        return databaseItemWriter; 
    } 
} 

第二步配置ItemSqlParameterSourceProvider 对象,JdbcBatchItemWriter 对象使用该对象获得SqlParameterSource 对象引用,用于获取命名参数的值。

因为命名参数名称与StudentDTO名称一致,可以直接使用BeanPropertyItemSqlParameterSourceProvider 类实现。
配置完使用ItemSqlParameterSourceProvider 对象后,CsvFileToDatabaseJobConfig代码如下:

import org.springframework.batch.item.ItemWriter; 
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider; 
import org.springframework.batch.item.database.ItemSqlParameterSourceProvider; 
import org.springframework.batch.item.database.JdbcBatchItemWriter; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 
  
import javax.sql.DataSource; 
  
@Configuration 
public class CsvFileToDatabaseJobConfig { 
      
    private static final String QUERY_INSERT_STUDENT = "INSERT " + 
            "INTO students(email_address, name, purchased_package) " + 
            "VALUES (:emailAddress, :name, :purchasedPackage)"; 
      
    @Bean 
    ItemWriter<StudentDTO> csvFileDatabaseItemWriter(DataSource dataSource,  
                                                     NamedParameterJdbcTemplate jdbcTemplate) { 
        JdbcBatchItemWriter<StudentDTO> databaseItemWriter = new JdbcBatchItemWriter<>(); 
        databaseItemWriter.setDataSource(dataSource); 
        databaseItemWriter.setJdbcTemplate(jdbcTemplate); 
  
        databaseItemWriter.setSql(QUERY_INSERT_STUDENT); 
  
        ItemSqlParameterSourceProvider<StudentDTO> paramProvider =  
                new BeanPropertyItemSqlParameterSourceProvider<>(); 
        databaseItemWriter.setItemSqlParameterSourceProvider(paramProvider); 
  
        return databaseItemWriter; 
    } 
} 

这就完成了命名参数方式配置。

3.总结

本文介绍了Spring batch写数据库,通过创建JdbcBatchItemWriter类。如果使用索引参数需要 ItemPreparedStatementSetter 接口,而使用命名参数需要实现ItemSqlParameterSourceProvider接口。如果使用命名参数且名称与DTO属性名称相同可以使用 BeanPropertyItemSqlParameterSourceProvider类。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/101980066