Java Spring批处理:使用自定义批处理大小将列表写入数据库表
背景 我有一份Spring批处理工作,其中:Java Spring批处理:使用自定义批处理大小将列表写入数据库表,java,spring-batch,spring-jdbc,jdbctemplate,itemwriter,Java,Spring Batch,Spring Jdbc,Jdbctemplate,Itemwriter,背景 我有一份Spring批处理工作,其中: FlatFileItemReader-从文件中一次读取一行 ItemProcesor-将文件中的行转换为列表,并返回列表。也就是说,文件中的每一行都被分解为一个列表(文件中的一行转换为多个输出行) ItemWriter-将列表写入数据库表。(我用过 解包从处理器接收的列表的实现 并授权给JdbcBatchItemWriter) 问题 在点2),处理器可以返回100000个MyObject实例的列表 在第3点),委托JdbcBatchItemWrit
FlatFileItemReader
-从文件中一次读取一行ItemProcesor
-将文件中的行转换为列表
,并返回列表
。也就是说,文件中的每一行都被分解为一个列表
(文件中的一行转换为多个输出行)ItemWriter
-将列表
写入数据库表。(我用过
解包从处理器接收的列表的实现
并授权给JdbcBatchItemWriter
)- 在点2),处理器可以返回100000个
实例的MyObject
列表
- 在第3点),委托
将最终将包含100000个对象的整个JdbcBatchItemWriter
列表写入数据库李>
我的问题是:
JdbcBatchItemWriter
不允许自定义批量大小。出于所有实际目的,该步骤的批处理大小=提交间隔。考虑到这一点,Spring批处理中是否有另一个ItemWriter
实现,它允许写入数据库并允许可配置的批处理大小?如果没有,如何着手自己编写自定义编写器来实现这一点?我看不到明显的方法来设置JdbcBatchItemWriter
上的批大小。但是,您可以扩展编写器并使用自定义的BatchPreparedStatementSetter
指定批大小。下面是一个简单的例子:
public class MyCustomWriter<T> extends JdbcBatchItemWriter<T> {
@Override
public void write(List<? extends T> items) throws Exception {
namedParameterJdbcTemplate.getJdbcOperations().batchUpdate("your sql", new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
// set values on your sql
}
@Override
public int getBatchSize() {
return items.size(); // or any other value you want
}
});
}
}
公共类MyCustomWriter扩展了JdbcBatchItemWriter{
@凌驾
public void write(List来自的答案和评论几乎涵盖了解决方案的所有方面,是公认的答案
如果有人感兴趣,下面是我使用的实现:
public class JdbcCustomBatchSizeItemWriter<W> extends JdbcDaoSupport implements ItemWriter<W> {
private int batchSize;
private ParameterizedPreparedStatementSetter<W> preparedStatementSetter;
private String sqlFileLocation;
private String sql;
public void initReader() {
this.setSql(FileUtilties.getFileContent(sqlFileLocation));
}
public void write(List<? extends W> arg0) throws Exception {
getJdbcTemplate().batchUpdate(sql, Collections.unmodifiableList(arg0), batchSize, preparedStatementSetter);
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
public void setPreparedStatementSetter(ParameterizedPreparedStatementSetter<W> preparedStatementSetter) {
this.preparedStatementSetter = preparedStatementSetter;
}
public void setSqlFileLocation(String sqlFileLocation) {
this.sqlFileLocation = sqlFileLocation;
}
public void setSql(String sql) {
this.sql = sql;
}
}
公共类JdbcCustomBatchSizeItemWriter扩展JDBCDAO支持实现ItemWriter{
私有整数批量大小;
私有参数化preparedStatementSetter preparedStatementSetter;
私有字符串sqlFileLocation;
私有字符串sql;
public void initReader(){
this.setSql(fileuties.getFileContent(sqlFileLocation));
}
公开无效写入(列表我不会这样做。它会带来可重启性问题。相反,请修改您的读卡器以生成单个项,而不是让处理器接收对象并返回列表。@MohmoudBenHassine这看起来很有希望。关于StagingItemWriter
示例,请不要使用BatchPreparedStatementSetter
,我可以简单地调用write
方法,将所需的批处理大小传递给它?是的,这是另一个选项。我已经得到了前进的必要方向。谢谢。很高兴它有帮助!但是,这很棘手。无论处理逻辑产生多少项,整个数据块都将有一个事务。例如,如果提交大小=10,且处理器为每个项目返回100个项目,则写入程序将在每个区块中接收1000个项目。即使jdbc batch_size=500,这些1000个项目也将在单个事务中提交。批次大小控制将向db发送的查询数量(在本例中为2个batchUpdate查询,每个批次500个项目)而不是多少个事务(在本例中是由Spring Batch驱动的单个事务)。没有问题。区块处理的思想是将整个区块作为一个单元进行处理(全部或全无语义)。只是想澄清您尝试自定义的批次大小不影响此模型(它只影响将向数据库发送多少查询)。将文件中的一行转换为多行所需的处理相对复杂,无法放入ItemReader
。如果考虑到我的作业永远不需要重新启动,我不需要重新启动作业,这种方法是否还有其他问题?