I have a Spring Batch job that calls another job in its first step / tasklet. Naturally, this does not work with how jobs handle transactions on default.
In my application, I don't really need transactions all that much, and the steps do not have a database connection anyway, so I'd rather just remove the transactions completely. For that, for each step of both jobs I did the following:
public Step stepX() {
return this.stepBuilderFactory
.get("stepX")
.tasklet(new StepXTasklet())
.transactionAttribute(transactionAttribute())
.build();
}
private TransactionAttribute transactionAttribute() {
DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
attribute.setPropagationBehavior(Propagation.SUPPORTS.value());
return attribute;
}
Still the application will throw this exception:
org.springframework.dao.OptimisticLockingFailureException: Attempt to update step execution id=1 with wrong version (2), where current version is 3
at org.springframework.batch.core.repository.dao.MapStepExecutionDao.updateStepExecution(MapStepExecutionDao.java:106)
at org.springframework.batch.core.repository.support.SimpleJobRepository.update(SimpleJobRepository.java:196)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy150.update(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
Which is how Spring Batch presents its internal TransactionSuspensionNotSupportedException
for some reason.
So something is still using transactions, I'm just not sure what, and how to remove them. Maybe the JobExecutionListener
? Maybe the chunks?
I'm leaning towards the chunks since after the second chunk (counted by the number of lines read) and before the third I get the output:
Commit failed while step execution data was already updated. Reverting to old version.
In case it makes a difference, the parent job is a "flow" job, the child job is a "reader-transformer-writer".
Which parts of the Spring Batch jobs framework uses transactions and how do I make sure these stop using them?