Spring Batch' RunIdIncrementer'没有产生下一个价值

时间:2013-07-31 16:29:25

标签: spring-batch

我在生产中运行了几个使用org.springframework.batch.core.launch.support.RunIdIncrementer的Spring Batch(2.1.9.RELEASE)作业。

偶尔会出现以下错误:

org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={run.id=23, tenant.code=XXX}.  If you want to run this job again, change the parameters.
    at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:122) ~[spring-batch-core-2.1.9.RELEASE.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_39]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_39]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_39]
    at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_39]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318) ~[spring-aop-3.1.1.RELEASE.jar:3.1.1.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) ~[spring-aop-3.1.1.RELEASE.jar:3.1.1.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) ~[spring-aop-3.1.1.RELEASE.jar:3.1.1.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) ~[spring-tx-3.1.1.RELEASE.jar:3.1.1.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.1.1.RELEASE.jar:3.1.1.RELEASE]
    at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.java:168) ~[spring-batch-core-2.1.9.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.1.1.RELEASE.jar:3.1.1.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) ~[spring-aop-3.1.1.RELEASE.jar:3.1.1.RELEASE]
    at sun.proxy.$Proxy64.createJobExecution(Unknown Source) ~[na:na]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:111) ~[spring-batch-core-2.1.9.RELEASE.jar:na]
    at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:349) [spring-batch-core-2.1.9.RELEASE.jar:na]
    at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:574) [spring-batch-core-2.1.9.RELEASE.jar:na]
    at (omitted for brevity)

来自各种XML上下文的抽样:

<bean
    id="jobParametersIncrementer"
    class="org.springframework.batch.core.launch.support.RunIdIncrementer" />

<batch:job id="rootJob"
    abstract="true"
    restartable="true">
    <batch:validator>
        <bean class="org.springframework.batch.core.job.DefaultJobParametersValidator">
            <property name="requiredKeys" value="tenant.code"/>
        </bean>
    </batch:validator>
</batch:job>

<batch:job id="rootJobWithIncrementer"
    abstract="true"
    parent="rootJob"
    incrementer="jobParametersIncrementer" />

我使用org.springframework.batch.core.launch.support.CommandLineJobRunner来执行作业:

java org.springframework.batch.core.launch.support.CommandLineJobRunner /com/XXX/job123/job123-context.xml job123 tenant.code=XXX -next 

所有作业(使用增量器)都将rootJobWithIncrementer作为父作业。

我做了很多研究,发现有些人遇到这个错误,成功地改变了事务管理器的隔离级别。我摆弄了几个级别,最后到达READ_COMMITED

<batch:job-repository
    id="jobRepository"
    data-source="oracle_hmp"
    transaction-manager="dataSourceTransactionManager"
    isolation-level-for-create="READ_COMMITTED"/>

根据我的理解,只有当相同的作业在多个进程的相同时间执行时才会发生此类错误 - 因此可能存在争用对于增量器。在这种情况下,的情况,但我们看到了错误。

关于可能导致此问题的任何想法?我应该尝试不同的隔离级别吗?还有别的吗?

谢谢!

有一个类似的问题here,但它没有得到很好的记录(也缺乏和回答)。

1 个答案:

答案 0 :(得分:0)

这可能是一个很长的过程,但我花了很长时间才弄明白,因为唯一的症状是偶尔得到你所描述的JobInstanceAlreadyCompleteException,所以我想我会建议它。

我使用的数据库是Oracle,我创建的BATCH_JOB_SEQBATCH_JOB_EXECUTION_SEQ的{​​{1}}都是10。

这会导致CACHE_SIZEJOB_INSTANCE_ID无法正确排序。 Spring批量假设最近的JOB_EXECUTION_ID是具有JOB_INSTANCE的{​​{1}}(参见max(JOB_INSTANCE_ID))。由于我的序列有时被抛弃,这种假设并不总是成立。

我通过将序列设置为org.springframework.batch.core.repository.dao.JdbcJobInstanceDao.FIND_LAST_JOBS_BY_NAME来修复它。

判断这可能是您的问题的一种简单方法是检查您的序列是否完全设置为CACHE和/或确保您的NO_CACHEJOB_INSTANCE_ID始终是新的运行。