Мой запрос выглядит примерно так:
Код: Выделить всё
select CHUNK_SIZE from SOME_TABLE_NAME where ID='some_id_param_value'
Я хочу получить этот CHUNK_SIZE из базы данных и динамически установить его на этапе задания.
Наше требование состоит в том, чтобы размер фрагмента менялся для шага на основе значения идентификатора подробности из которых хранятся в таблице БД. Например:
ID
CHUNK_SIZE
01
1000
02
2500
Я знаю, что компоненты в задании устанавливаются на время настройки, а параметры задания передаются во время выполнения при запуске задания.
РЕДАКТИРОВАТЬ:
Пример, предоставленный MahmoudBenHassine, использует @JobScope и получает доступ к jobParameters в шаговом компоненте с помощью @Value(" #{jobParameters['id']}"). Я попытался реализовать аналогичный подход с использованием jobExecutionContext следующим образом:
- Извлекал chunkSize из таблицы базы данных в
метод beforeStep StepExecutionListener и установите его в.Код: Выделить всё
ExecutionContext
- Аннотировал степ-компонент с помощью @JobScope и использовал
для доступа к нему в шаге
Код: Выделить всё
@Value("#{jobExecutionContext['chunk']}")
bean. - Но я столкнулся со следующей ошибкой:
Код: Выделить всё
Error creating bean with name 'scopedTarget.step' defined in class path resource [com/sample/config/SampleBatchConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.core.Step]: Factory method 'step' threw exception; nested exception is java.lang.NullPointerException
Нужно ли его как-то продвигать, чтобы к нему можно было получить доступ в степ-компоненте? Если да, то мы будем очень признательны за небольшой пример или руководство.
Мой класс контроллера:
Код: Выделить всё
@RestController
public class SampleController {
@Autowired
JobLauncher sampleJobLauncher;
@Autowired
Job sampleJob;
@GetMapping("/launch")
public BatchStatus launch(@RequestParam(name = "id", required = true) String id){
Map map = new HashMap();
map.put("id", new JobParameter(id));
map.put("timestamp", new JobParameter(System.currentTimeMillis));
JobParameters params = new JobParameters(map);
JobExecution j = sampleJobLauncher.run(sampleJob, params);
return j.getStatus();
}
}
Код: Выделить всё
@Configuration
public class SampleBatchConfig{
@Autowired
private JobBuilderFactory myJobBuilderFactory;
@Autowired
private StepBuilderFactory myStepBuilderFactory;
@Autowired
private MyRepoClass myRepo; // this class contains the jdbc method to fetch chunksize from the db table
@Autowired
MyReader myReader;
@Autowired
MyWriter myWriter;
@Bean
@JobScope
public Step sampleStep(@Value("#{jobExecutionContext['chunk']}") Integer chunkSize){
return myStepBuilderFactory.get("sampleStep")
.chunk(chunkSize) //TODO ~instead of hardcoding the chunkSize or getting it from the properties file using @Value, the requirement is to fetch it from the db table using the above mentioned query with id job parameter and set it here
.reader(myReader.sampleReader())
.writer(myWriter.sampleWriter())
.listener(new StepExecutionListener() {
@Override
public void beforeStep(StepExecution stepExecution) {
int chunk = myRepo.findChunkSize(stepExecution.getJobExecution().getExecutionContext().get("id")); // this method call fetches chunksize from the db table using the id job parameter
stepExecution.getJobExecution().getExecutionContext().put("chunk", chunk);
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
})
.build();
}
@Bean
public Job job(){
return myJobBuilderFactory.get("sampleJob")
.incrementer(new RunIdIncrementer())
.start(sampleStep(null))
.build();
}
}
Задание может состоять из нескольких шагов с разными размерами фрагментов, и в этом случае размер фрагмента должен извлекаться отдельно для каждого шага. .
РЕДАКТИРОВАНИЕ 2:
Изменение моего определения шага следующим образом работает, но есть проблема.
Здесь читатель читает список, имеющий 17 предметов в блоке размером 4.
Код: Выделить всё
@Bean
@JobScope
public Step sampleStep(@Value("#{jobParameters['id']}") Integer id){
int chunkSize = myRepo.findChunkSize(id); // this method call fetches chunksize from the db table using the id job parameter
return myStepBuilderFactory.get("sampleStep")
.chunk(chunkSize)
.reader(myReader.sampleReader())
.writer(myWriter.sampleWriter())
.listener(new ChunkListenerSupport() {
@Override
public void afterChunk(ChunkContext context) {
System.out.println("MyJob.afterChunk");
}
@Override
public void beforeChunk(ChunkContext context) {
System.out.println("MyJob.beforeChunk");
}
})
.build();
}
Код: Выделить всё
2021-05-03 15:06:44.859 INFO 11924 --- [nio-8081-exec-1] o.s.batch.core.job.SimpleStepHandler : Executing step: [sampleStep]
MyJob.beforeChunk
item = 1
item = 2
item = 3
item = 4
MyJob.afterChunk
MyJob.beforeChunk
item = 5
item = 6
item = 7
item = 8
MyJob.afterChunk
MyJob.beforeChunk
item = 9
item = 10
item = 11
item = 12
MyJob.afterChunk
MyJob.beforeChunk
item = 13
item = 14
item = 15
item = 16
MyJob.afterChunk
MyJob.beforeChunk
item = 17
MyJob.afterChunk
Код: Выделить всё
2021-05-03 15:11:02.427 INFO 11924 --- [nio-8081-exec-4] o.s.batch.core.job.SimpleStepHandler : Executing step: [sampleStep]
MyJob.beforeChunk
MyJob.afterChunk
Подробнее здесь: https://stackoverflow.com/questions/673 ... ng-from-db