1

背景

我有一个 Spring Batch工作,其中:

  1. FlatFileItemReader- 从文件中一次读取一行
  2. ItemProcesor- 将文件中的行转换为 aList<MyObject>并返回List. 也就是说,文件中的每一行都被分解为一个List<MyObject>(文件中的 1 行转换为许多输出行)。
  3. ItemWriter- 将 写入List<MyObject>数据库表。(我使用这个 实现来解压从处理器和委托接收到的列表到 a JdbcBatchItemWriter

问题

  • 在第 2 点)处理器可以返回List100000 个MyObject实例。
  • 在第 3 点),委托JdbcBatchItemWriter最终会将List包含 100000 个对象的整个数据写入数据库。

我的问题是:JdbcBatchItemWriter不允许自定义批量大小。出于所有实际目的,该步骤的批大小 = 提交间隔。考虑到这一点,Spring Batch中是否有另一种ItemWriter可用的实现,它允许写入数据库并允许可配置的批量大小?如果没有,如何自己编写自定义作家来实现这一目标?

4

3 回答 3

1

我看不到在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
            }
        });
    }

}

示例中的StagingItemWriter也是如何使用自定义的示例BatchPreparedStatementSetter

于 2019-10-24T09:41:22.950 回答
1

Mahmoud Ben Hassine的答案和评论几乎涵盖了解决方案的所有方面,并且是公认的答案。

如果有人感兴趣,这是我使用的实现:

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;
    }
}

笔记 :

  1. 的使用Collections.unmodifiableList避免了任何显式转换的需要。
  2. sqlFileLocation用来指定一个包含 sql 的外部文件,并FileUtilities.getfileContents简单地返回这个 sql 文件的内容。这可以跳过,也可以sql在创建 bean 时直接将 传递给类。
于 2019-10-24T13:49:04.443 回答
0

我不会这样做的。它提出了可重启性的问题。相反,修改您的阅读器以生成单个项目,而不是让您的处理器接收一个对象并返回一个列表。

于 2019-10-24T15:52:59.300 回答