Весенний пакет — данные не обрабатываются полностью перед чтением следующей страницы из БД

#spring #out-of-memory #spring-batch

Вопрос:

У меня есть таблица MY_TABLE , которая содержит около 500 тысяч строк, считыватель должен прочитать из этой таблицы pageSize как 100, затем он должен обработать эту страницу как мой процессор и записать в БД в соответствии с моим автором.

Что происходит, так это то, что читатель продолжает читать на 100 100 страницах до тех пор, пока не выдохнется и не выдаст OutOfMemoryError около 400 тысяч записей.

Я не уверен, почему это не работает на страницах и chunk вообще, и почему он считывает все данные из таблицы, а не работает только с pageSize суммой.

Ниже приведен код, который у меня есть для step и reader .

 public Step customStep(StepBuilderFactory stepBuilderFactory, ItemReader<CustomEntityClass> reader,  ItemProcessor<CustomEntityClass, List<CustomEntityClassSecond>> processor, ItemWriter<List<CustomEntityClassSecond>> writer)  {  DefaultResultCompletionPolicy comp = new DefaultResultCompletionPolicy();   return stepBuilderFactory.get(BatchConstants.STEP_NAME)  .<CustomEntityClass, List<CustomEntityClassSecond>> chunk(comp)  .reader(reader)  .processor(processor)  .writer(writer).build();  }   @Bean  public Step purgeTasklet(StepBuilderFactory stepBuilderFactory, Tasklet tasklet)  {  return stepBuilderFactory.get(BatchConstants.TASKLET_NAME).tasklet(tasklet).build();  }   @Bean  public ItemReader<CustomEntityClass> customReader(@Qualifier(DATA_SOURCE) DataSource dataSource)  throws Exception  {  JdbcPagingItemReader<CustomEntityClass> reader = new JdbcPagingItemReader<>();  SqlPagingQueryProviderFactoryBean pagingQueryFactoryBean = new SqlPagingQueryProviderFactoryBean();  pagingQueryFactoryBean.setSelectClause("*");  pagingQueryFactoryBean.setFromClause("MY_TABLE");  pagingQueryFactoryBean.setWhereClause("CREATIONDATE <= :creationDate");  pagingQueryFactoryBean.setSortKey("id");  pagingQueryFactoryBean.setDataSource(dataSource);  reader.setQueryProvider(pagingQueryFactoryBean.getObject());  reader.setPageSize(100);  reader.setDataSource(dataSource);  reader.setRowMapper(new BeanPropertyRowMapper<>(CustomEntityClass.class));   Calendar calendar = Calendar.getInstance();  calendar.add(Calendar.DAY_OF_MONTH, -1);   DateFormat df = new SimpleDateFormat(BatchConstants.CREATION_DATE_FORMAT);  String creationDate = df.format(calendar.getTime());  Map<String, Object> parameters = new HashMap<>();  parameters.put("creationDate", creationDate);  reader.setParameterValues(parameters);  return reader;  }```  

Комментарии:

1. Может ли этот класс быть проблемой здесь для использования в блоке? DefaultResultCompletionPolicy comp = new DefaultResultCompletionPolicy(); Должен ли я использовать SimpleCompletionPolicy?

Ответ №1:

Размер блока, который использует Spring Batch, не зависит от размера страницы в считывателе. Имеет смысл устанавливать их последовательно, но это не обязательно строго.

Это должно работать, как и ожидалось, с

 stepBuilderFactory.get(BatchConstants.STEP_NAME)  .<CustomEntityClass, List<CustomEntityClassSecond>>chunk(100)  .reader(reader)  .processor(processor)  .writer(writer).build();  

Затем Spring Batch будет использовать 100 элементов на кусок, что в точности соответствует содержимому одной запрашиваемой страницы.

Комментарии:

1. можете ли вы сказать мне, почему вы использовали размер фрагмента int, а не сказали «новая политика simplecompletion(100)»?

2. Это равносильно. Если вы передадите размер блока int, Spring Batch создаст политику для вас. Это дело вкуса, но я бы предпочел передать int, так как это делает код приложения немного более компактным.