Spring Batch: запись списка в таблицу базы данных с использованием настраиваемого размера пакета
Задний план
У меня есть задание Spring Batch, где:
FlatFileItemReader
- Читает по одной строке из файлаItemProcesor
- Преобразует строку из файла вList<MyObject>
и возвращаетList
. То есть каждая строка в файле разбита наList<MyObject>
(1 строка в файле преобразована во многие выходные строки).ItemWriter
- пишетList<MyObject>
в таблицу базы данных. (Я использовал эту реализацию для распаковки списка, полученного от процессора и делегатов, вJdbcBatchItemWriter
)
Вопрос
- В пункте 2) процессор может вернуть
List
из 100000MyObject
экземпляры. - В пункте 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;
}
}
Примечание:
- Использование
Collections.unmodifiableList
предотвращает необходимость в явном приведении типов. - я использую
sqlFileLocation
чтобы указать внешний файл, содержащий sql иFileUtilities.getfileContents
просто возвращает содержимое этого sql-файла. Это можно пропустить, и можно сразу передатьsql
в класс при создании bean-компонента.
Я бы не стал этого делать. Это создает проблемы для перезапуска. Вместо этого модифицируйте читателя, чтобы он создавал отдельные элементы, а не заставлял процессор принимать объект и возвращать список.