Spring Batch: запись списка в таблицу базы данных с использованием нестандартного размера пакета - PullRequest
0 голосов
/ 24 октября 2019

Фон

У меня есть задание 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 не допускает нестандартный размер партии. Для всех практических целей batch-size = commit-interval для шага. Имея это в виду, существует ли другая реализация ItemWriter, доступная в Spring Batch , которая позволяет выполнять запись в базу данных и позволяет настраивать размер пакета? Если нет, то как мне написать собственного писателя, чтобы добиться этого?

Ответы [ 3 ]

1 голос
/ 24 октября 2019

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

0 голосов
/ 24 октября 2019

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

0 голосов
/ 24 октября 2019

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

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

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 классу.
...