我有简单的Spring-Service,其中包括(以及其他任务)使用以下代码启动spring批处理作业:
@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);
}
只要在调用Serivce-Method时没有事务处于活动状态,这样就可以正常工作。但是,对于活动事务,我会遇到此异常:
Caused by: java.lang.IllegalStateException: Existing transaction detected in JobRepository. Please fix this and try again (e.g. remove @Transactional annotations from client).
我无法轻松删除现有的交易,因为由于某些框架代码不在我的范围内,因此暗示了这一点。
那么,我怎样才能在这种背景下开始这项工作呢?新工作不应该使用现有的交易。它可能只是启动自己的事务 - 但如何配置它以使其工作?
答案 0 :(得分:4)
我有类似的问题。特别是,我从一个用@Transactional(propagation = Propagation.REQUIRES_NEW)
注释的类中开始工作。为了解决这个问题,我从某个地方开始工作,那里没有活动交易。然后我如上所述遇到了你的问题 - 这就是我解决它的方法:
在JobRepository上将validateTransactionState
设置为false - 它现在忽略了在调用的类ItemProcessor
中自动创建的事务(因为所述类使用@Transcational注释,如上所述)。
这使我的工作运行得很好。但是,我不确定我现在是在处理2次公开交易,并且想确定我不是。所以我还删除了类级别的transcational注释,并将其移动到所有公共方法,除了我的Itemprocessor调用的方法。因此我解决了这个问题。
答案 1 :(得分:2)
使用AbstractJobRepositoryFactoryBean.ValidateTransactionState
,但要小心使用(警告:前方龙)。
要使用其他交易,您可以使用标记为@Transactional()的方法SimpleJobLauncher.executor
注入自定义Executor.run
(或创建自定义JobLauncher
并对方法{{1执行相同操作}})。
我没有尝试,因为我没有遇到问题,但希望可以帮助。
答案 2 :(得分:2)
我的解决方案是启动作业的方法需要使用@Transactional(propagation = Propagation.NOT_SUPPORTED)
进行注释,这将暂停当前事务并在执行后恢复。
如果您需要与默认设置不同的内容,可以在读者和作者身上设置transactionAttribute
。
setValidateTransactionState(false)
或JobRepositoryFactoryBean
JobRepository
答案 3 :(得分:0)
我通过创建一个单独的bean AsyncJobLauncher来解决这个问题,它有一个与JobLauncher具有相同签名的run方法,并委托给真实的那个,但标有Spring的@Async。因此,工作的启动发生在新线程的后台,因此它在自己的事务中。