Spring Batch: запись списка в таблицу базы данных с использованием настраиваемого размера пакета

Задний план

У меня есть задание Spring Batch, где:

  1. FlatFileItemReader - Читает по одной строке из файла
  2. ItemProcesor - Преобразует строку из файла в List<MyObject> и возвращает List. То есть каждая строка в файле разбита наList<MyObject> (1 строка в файле преобразована во многие выходные строки).
  3. ItemWriter - пишет List<MyObject>в таблицу базы данных. (Я использовал эту реализацию для распаковки списка, полученного от процессора и делегатов, вJdbcBatchItemWriter)

Вопрос

  • В пункте 2) процессор может вернуть List из 100000 MyObject экземпляры.
  • В пункте 3) делегат JdbcBatchItemWriter в конечном итоге напишет весь List с 100000 объектов в базу.

Мой вопрос: JdbcBatchItemWriterне допускает нестандартного размера партии. Для всех практических целей размер пакета = интервал фиксации для шага. Имея это в виду, есть ли еще одна реализацияItemWriterдоступен в Spring Batch, который позволяет записывать в базу данных и позволяет настраивать размер пакета? Если нет, то как мне самому написать нестандартного писателя, чтобы добиться этого?

3 ответа

Решение

Я не вижу очевидного способа установить размер партии на 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 также.

Ответ Махмуда Бен Хассина и комментарии в значительной степени охватывают все аспекты решения и являются принятым ответом.

Вот реализация, которую я использовал, если кому-то интересно:

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-компонента.

Я бы не стал этого делать. Это создает проблемы для перезапуска. Вместо этого модифицируйте читателя, чтобы он создавал отдельные элементы, а не заставлял процессор принимать объект и возвращать список.

Другие вопросы по тегам