我有一份春季批次工作,我想做以下工作.
Step 1 -
Tasklet - Create a list of dates, store the list of dates in the job execution context.
Step 2 -
JDBC Item Reader - Get list of dates from job execution context.
Get element(0) in dates list. Use is as input for jdbc query.
Store element(0) date is job execution context
Remove element(0) date from list of dates
Store element(0) date in job execution context
Flat File Item Writer - Get element(0) date from job execution context and use for file name.
Then using a job listener repeat step 2 until no remaining dates in the list of dates.我已经创建了这个作业,第一次执行第二步还行,但是第二步并没有像我想要的那样重复。我之所以知道这一点,是因为当我通过代码进行调试时,它只会中断步骤2的初始运行。
但是,它确实会像下面这样继续给我消息,就好像它正在运行步骤2一样,即使我知道它不是。
2016-08-10 22:20:57.842 INFO 11784 --- [ main] o.s.batch.core.job.SimpleStepHandler : Duplicate step [readStgDbAndExportMasterListStep] detected in execution of job=[exportMasterListCsv]. If either step fails, both will be executed again on restart.
2016-08-10 22:20:57.846 INFO 11784 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [readStgDbAndExportMasterListStep]这将以一个永无止境的循环结束。
有人能帮我弄清楚为什么我的stpe 2只运行一次吗?
提前感谢
我为我的代码添加了两个链接到PasteBin,以避免污染这个帖子。
http://pastebin.com/QhExNikm (Job )
http://pastebin.com/sscKKWRk (通用作业控制)
http://pastebin.com/Nn74zTpS (步骤执行侦听器)
发布于 2016-08-15 08:09:13
基于我们对Spring batch execute dynamically generated steps in a tasklet的讨论,我试图回答有关如何在实际执行作业之前访问jobParameter的问题。
我假设存在that调用,它将执行批处理。一般来说,这将需要采取以下步骤。1.接收rest调用及其参数的代码2.创建新的some上下文(有方法重用现有的上下文并再次启动作业,但在重用步骤、读者和作者时存在一些问题)。
最简单的解决方案是将从服务接收的作业参数存储为系统属性,然后在步骤3中构建作业时访问该属性。但是,如果多个用户同时启动作业,则可能会导致问题。
在加载参数时,还有其他方法将参数传递到loaded上下文中。但这取决于设置上下文的方式。例如,如果在步骤2中直接使用SpringBoot,则可以编写如下方法:
private int startJob(Properties jobParamsAsProps) {
SpringApplication springApp = new SpringApplication(.. my config classes ..);
springApp.setDefaultProperties(jobParamsAsProps);
ConfigurableApplicationContext context = springApp.run();
ExitCodeGenerator exitCodeGen = context.getBean(ExitCodeGenerator.class);
int code = exitCodeGen.getExitCode();
context.close();
return cod;
}通过这种方式,您可以使用标准值或ConfigurationProperties注释正常地访问这些属性。
发布于 2016-08-10 17:37:38
从您的问题和代码中,我推断,根据您检索的日期的数量(在实际作业开始之前发生的情况),您将对有日期的时间执行一个步骤。
我建议改变设计。创建一个java类,将日期作为列表获取,并根据该列表动态创建您的步骤。就像这样:
@EnableBatchProcessing
public class JobConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private JobDatesCreator jobDatesCreator;
@Bean
public Job executeMyJob() {
List<Step> steps = new ArrayList<Step>();
for (String date : jobDatesCreator.getDates()) {
steps.add(createStep(date));
}
return jobBuilderFactory.get("executeMyJob")
.start(createParallelFlow(steps))
.end()
.build();
}
private Step createStep(String date){
return stepBuilderFactory.get("readStgDbAndExportMasterListStep" + date)
.chunk(your_chunksize)
.reader(your_reader)
.processor(your_processor)
.writer(your_writer)
.build();
}
private Flow createParallelFlow(List<Step> steps) {
SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
// max multithreading = -1, no multithreading = 1, smart size = steps.size()
taskExecutor.setConcurrencyLimit(1);
List<Flow> flows = steps.stream()
.map(step -> new FlowBuilder<Flow>("flow_" + step.getName()).start(step).build())
.collect(Collectors.toList());
return new FlowBuilder<SimpleFlow>("parallelStepsFlow")
.split(taskExecutor)
.add(flows.toArray(new Flow[flows.size()]))
.build();
}
}编辑:添加了"jobParameter“输入(也略有不同)
在类路径的某个位置添加以下示例.properties文件:
sql.statement="select * from awesome"并将以下注释添加到JobDatesCreator类中
@PropertySource("classpath:example.properties")您还可以提供特定的sql语句作为命令行参数。在春季文件中:
您可以使用特定的命令行开关启动(例如,java -jar app.jar -name=“Spring”)。
有关此问题的更多信息,请参见http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
获取日期的类(为什么要使用tasklet进行此操作?):
@PropertySource("classpath:example.properties")
public class JobDatesCreator {
@Value("${sql.statement}")
private String sqlStatement;
@Autowired
private CommonExportFromStagingDbJobConfig commonJobConfig;
private List<String> dates;
@PostConstruct
private void init(){
// Execute your logic here for getting the data you need.
JdbcTemplate jdbcTemplate = new JdbcTemplate(commonJobConfig.onlineStagingDb);
// acces to your sql statement provided in a property file or as a command line argument
System.out.println("This is the sql statement I provided in my external property: " + sqlStatement);
// for now..
dates = new ArrayList<>();
dates.add("date 1");
dates.add("date 2");
}
public List<String> getDates() {
return dates;
}
public void setDates(List<String> dates) {
this.dates = dates;
}
}我还注意到,您有很多重复的代码,可以很容易地重构。现在,对于每一位作家来说,都有这样的东西:
@Bean
public FlatFileItemWriter<MasterList> division10MasterListFileWriter() {
FlatFileItemWriter<MasterList> writer = new FlatFileItemWriter<>();
writer.setResource(new FileSystemResource(new File(outDir, MerchHierarchyConstants.DIVISION_NO_10 )));
writer.setHeaderCallback(masterListFlatFileHeaderCallback());
writer.setLineAggregator(masterListFormatterLineAggregator());
return writer;
}请考虑使用类似的方法:
public FlatFileItemWriter<MasterList> divisionMasterListFileWriter(String divisionNumber) {
FlatFileItemWriter<MasterList> writer = new FlatFileItemWriter<>();
writer.setResource(new FileSystemResource(new File(outDir, divisionNumber )));
writer.setHeaderCallback(masterListFlatFileHeaderCallback());
writer.setLineAggregator(masterListFormatterLineAggregator());
return writer;
}由于并不是所有的代码都可以正确地复制您的问题,因此这个答案是解决问题的建议/指示。
https://stackoverflow.com/questions/38871808
复制相似问题