Start a spring batch job when already within a transaction

杀马特。学长 韩版系。学妹 提交于 2020-12-29 07:14:04

问题


I have simple Spring-Service that (among other tasks) starts a spring batch job with the following code:

@Autowired
private JobRegistry jobRegistry;

@Autowired
private JobLauncher jobLauncher;

public void startMyJob() {
    Job job = jobRegistry.getJob("myJobName");
    JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
    jobLauncher.run(job, jobParameters);
}

This works fine, as long as there is no transaction active when the Serivce-Method is called. However, with an active transaction, I get this exception:

Caused by: java.lang.IllegalStateException: Existing transaction detected in JobRepository. Please fix this and try again (e.g. remove @Transactional annotations from client).

I cannot easily remove the existing transaction, since it is implied due to some framework code that is not within my reach.

So, how can I start the job anyway within this context? The new job just should not use the existing transaction. It could just start its own transaction - but how to configure it to make it work?


回答1:


Use AbstractJobRepositoryFactoryBean.ValidateTransactionState, but use carefully (Warning: Dragons ahead).

To use another transaction you can inject a custom SimpleJobLauncher.executor with method Executor.run marked as @Transactional() (or create a custom JobLauncher and do the same trick on method run).

I haven't tried because I haven't faced the problem, but hope can help.




回答2:


I had a similar problem. In particular, I was starting my jobs from within a class that was annotated with @Transactional(propagation = Propagation.REQUIRES_NEW). To work around this, I started my jobs from a somewhere, where I had no active transaction. Then I ran into your problem as described above - and here is how I solved it:

set validateTransactionStateto false on the JobRepository - it now ignored the transactions that were automatically created in the class my ItemProcessor called (because said class was annotated with @Transcational, as explained above).

This made my jobs run just fine. However, I wasn't sure if I was now dealing with 2 open transactions and wanted to be sure I was not. So I also removed the transcational annnotation on the class level and moved it to all public methods, except the ones called by my Itemprocessor. Thus I solved the issue.




回答3:


My solution was that the method starting the job needed to be annotated with @Transactional(propagation = Propagation.NOT_SUPPORTED) this would suspend the current transaction and resume after execution.

You can set transactionAttribute on your readers and writers if you need anything different from defaults.

I did not need setValidateTransactionState(false) on the JobRepositoryFactoryBean or JobRepository




回答4:


I've dealt with this by creating a separate bean AsyncJobLauncher which has a run method with the same signature as JobLauncher and delegates to the real one, but marked with Spring's @Async. So, the launching of the job happened in the background on a new thread, so it was in its own transaction.



来源:https://stackoverflow.com/questions/18125394/start-a-spring-batch-job-when-already-within-a-transaction

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!