【问题标题】:Start a spring batch job when already within a transaction已经在事务中时启动弹簧批处理作业
【发布时间】:2013-08-08 11:55:49
【问题描述】:

我有一个简单的 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).

我无法轻易删除现有事务,因为某些框架代码不在我的范围内,因此它是隐含的。

那么,在这种情况下,我该如何开始工作呢?新工作不应该使用现有事务。它可以开始自己的事务 - 但是如何配置它以使其工作?

【问题讨论】:

    标签: java spring transactions spring-batch


    【解决方案1】:

    我遇到了类似的问题。特别是,我从一个带有@Transactional(propagation = Propagation.REQUIRES_NEW) 注释的类中开始我的工作。为了解决这个问题,我从一个没有活跃交易的地方开始我的工作。然后我遇到了如上所述的问题 - 这是我解决它的方法:

    在 JobRepository 上将 validateTransactionState 设置为 false - 它现在忽略了在我的 ItemProcessor 调用的类中自动创建的事务(因为如上所述,该类使用 @Transcational 进行了注释)。

    这使我的工作运行良好。但是,我不确定我现在是否正在处理 2 笔未结交易,并想确定我不是。因此,我还删除了类级别的跨类注解,并将其移至所有公共方法,但我的 Itemprocessor 调用的方法除外。因此我解决了这个问题。

    【讨论】:

      【解决方案2】:

      我的解决方案是启动作业的方法需要使用@Transactional(propagation = Propagation.NOT_SUPPORTED) 进行注释,这将暂停当前事务并在执行后恢复。

      如果您需要与默认值不同的任何内容,您可以在您的读者和作者上设置transactionAttribute

      我在JobRepositoryFactoryBeanJobRepository 上不需要setValidateTransactionState(false)

      【讨论】:

        【解决方案3】:

        我通过创建一个单独的 bean AsyncJobLauncher 来解决这个问题,它有一个与 JobLauncher 签名相同的 run 方法,并委托给真实的,但用 Spring 的 @Async 标记。因此,作业的启动发生在新线程的后台,所以它在自己的事务中。

        【讨论】:

          【解决方案4】:

          使用AbstractJobRepositoryFactoryBean.ValidateTransactionState,但要小心使用(警告:前方有龙)。

          要使用另一个事务,您可以使用标记为@Transactional() 的方法Executor.run 注入自定义SimpleJobLauncher.executor(或创建自定义JobLauncher 并对方法run 执行相同的技巧)。

          我没有尝试过,因为我没有遇到过这个问题,但希望可以提供帮助。

          【讨论】:

          • 感谢您的回答!用 (at)Transactional 标记 run-Method 本身并不能解决问题,因为 Validator 仍然会找到现有的事务。我现在将两者结合起来:标记 run-Method (at)Transactional 并禁用验证器 - 在我的开发环境中工作正常,尽管我对这个解决方案没有信心。
          • 嗨@Jack,你如何禁用验证器?
          • 它是 JobRepository 的一个属性。定义 jobRepository Bean 时,将 validateTransactionState 属性设置为 false。
          • @Transactional(propagation = Propagation.NOT_SUPPORTED) 在自定义作业启动器的运行方法上为我解决了问题。根据下面答案中的提示,无需禁用验证器。
          猜你喜欢
          • 2017-11-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多