我想使用Spring批处理(V3.0.9)重新启动功能,以便在jobinstance
重新启动时,流程步骤从上一个失败的块点向前读取。只要不对myBatisPagingItemReader
bean方法使用@stepscope
批注,我的重新启动就可以正常工作。
我使用了@stepscope
以便在我的myBatisPagingItemReader
bean方法@value(“#{jobParameters['run-date']}”)
如果对myBatisPagingItemReader()
bean方法使用@stepscope
我用下面的例子解释了这个问题。
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory,
ItemReader<Model> myBatisPagingItemReader,
ItemProcessor<Model, Model> itemProcessor,
ItemWriter<Model> itemWriter) {
return stepBuilderFactory.get("data-load")
.<Model, Model>chunk(10)
.reader(myBatisPagingItemReader)
.processor(itemProcessor)
.writer(itemWriter)
.listener(itemReadListener())
.listener(new JobParameterExecutionContextCopyListener())
.build();
}
@Bean
public Job job(JobBuilderFactory jobBuilderFactory, @Qualifier("step1")
Step step1) {
return jobBuilderFactory.get("load-job")
.incrementer(new RunIdIncrementer())
.start(step1)
.listener(jobExecutionListener())
.build();
}
@Bean
@StepScope
public ItemReader<Model> myBatisPagingItemReader(
SqlSessionFactory sqlSessionFactory,
@Value("#{JobParameters['run-date']}") String runDate)
{
MyBatisPagingItemReader<Model> reader = new
MyBatisPagingItemReader<>();
Map<String, Object> parameterValues = new HashMap<>();
parameterValues.put("runDate", runDate);
reader.setSqlSessionFactory(sqlSessionFactory);
reader.setParameterValues(parameterValues);
reader.setQueryId("query");
return reader;
}
}
重新启动示例当我将@stepscope
注释使用到MyBatiSpagingItemReader()
时,读取器正在获取5条记录,而我将块大小(commit-interval)设置为3。
作业实例-01-作业参数-01/02/2019。
块-1:
-进程记录-1
-进程记录-2
-进程记录-3
写入器-写入所有3条记录
块-1提交成功
块2:
进程记录-4
进程记录-5-抛出和异常
作业完成并设置为“失败”状态
现在使用相同的作业参数再次重新启动作业。
作业实例-01-作业参数-01/02/2019。
chunk-1:
进程记录-1
进程记录-2
进程记录-3
writer-写入所有3条记录
chunk-1提交成功
块2:
进程记录-4
进程记录-5-抛出和异常
作业完成并设置为“失败”状态
MyBatiSpagingItemReader()
bean方法上的@stepscope
注释创建了一个新实例,请参阅下面的日志消息。
在scope=step,name=ScopedTarget中创建对象。MyBatiSpagingItemReader
在scope=step,name=ScopedTarget中注册了销毁回调。MyBatiSpagingItemReader
因为是新实例,所以它从start开始进程,而不是从Chunk-2开始。
如果不使用@stepscope
,它将从块-2重新启动,因为重新启动的作业步骤集-mybatispagingitemreader.read.count=3。
这里的问题是,您返回的是ItemReader
而不是完全限定类(MyBatispagingItemReader
)或至少是ItemStreamReader
。当您使用Spring Batch的step范围时,我们会创建一个代理来允许后期初始化。代理基于方法的返回类型(在您的示例中为itemreader
)。您遇到的问题是,因为代理是itemreader
,所以Spring Batch不知道您的bean也实现了itemstream
,而正是该接口启用了可重启性。默认情况下,Spring批处理将自动为您注册itemstream
类型的所有bean(您也可以自己显式注册bean,但通常不需要)。
要解决您的问题,以下方法应该起作用(注意返回类型中的更改):
@Bean
@StepScope
public MyBatisPagingItemReader<Model> myBatisPagingItemReader(
SqlSessionFactory sqlSessionFactory,
@Value("#{JobParameters['run-date']}") String runDate) {
MyBatisPagingItemReader<Model> reader =
new MyBatisPagingItemReader<>();
Map<String, Object> parameterValues = new HashMap<>();
parameterValues.put("runDate", runDate);
reader.setSqlSessionFactory(sqlSessionFactory);
reader.setParameterValues(parameterValues);
reader.setQueryId("query");
return reader;
}
这就是为什么我建议在可能的情况下,当使用@bean
注释方法时,应该返回尽可能具体的类型,以允许Spring尽可能地提供帮助。
我是C编程的初学者,如果我能得到一些关于如何重新启动程序的提示,我将不胜感激?我目前正在开发一个猜测游戏,用户有10次尝试猜测随机提供的秘密号码。我希望该程序能够从一开始就为用户提供新一轮游戏(尝试次数1猜测次数:),这意味着重新运行该程序。 以下是节目:
我有一个活动,我们称之为FirstActivity.java,它有一个带有通过片段实例化的导航抽屉的actionBar。在这个片段NavigationDrawerFragment.java中,为了实例化ActionBar,我将方法onCreateOptionsMenu(菜单菜单,MenuInflater inflater)、onOptionsItemSelected(MenuItem项)和onPr
我使用的是Spring批处理版本2.2.4.Release,我试图用有状态的ItemReader、ItemProcessor和ItemWriter bean编写一个简单的示例。 在我的集成测试中,我在一个内部静态java配置类中声明bean,如下所示: 这个测试通过了。 但是,一旦我将StatefulItemReader定义为step范围的bean(这对于有状态的读取器更好),“Before st
我正在尝试重新开始使用Spring Boot开发工具。我一直遵循此处提供的说明:https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html 我正在使用gradle,并将其包含在我的build.gradle文件中: 我创建jar文件并运行jar文件: 我能够通过Intellij连接到正
我有一个spring批处理作业,从CSV文件读取并写入数据库。我想让它重新启动。例如,如果在读取文件或写入db时出现异常,导致作业失败,则应从失败的同一点/块重新开始,而不是从头开始读取整个文件。 我正在从一个endpoint触发作业启动器,并在我的控制器中配置了它。 目前,我正在通过控制器将参数(这是一个唯一的标识符/数字)传递给作业参数,以运行新的作业实例。如果作业失败,我将使用与GET请求中
我在网上看了很多关于< code > spring-boot-dev tools 的文章和问题,但是仍然不明白为什么它对我不起作用。每次运行我的应用程序,我都会得到以下信息: 每当我更改其中一个控制器文件时,什么也没发生。所以我遇到了一篇文章,提到我应该尝试将添加到我的应用程序属性文件中。使用 src 将不起作用,因为它会认为这是一个绝对路径,所以我将其更改为 。完成此操作后,将新endpoint