为什么在步骤中将 TransactionManager 设置为 JPATransactionManager 不正确?

Why is setting TransactionManager as JPATransactionManager in a Step not correct?

我正在使用 Spring Batch 和 JPA,我遇到了 TransactionManager bean 冲突。我通过在一个步骤中将 TransactionManager 设置为 JpaTransactionManager 找到了解决方案。但是根据这个link(https://github.com/spring-projects/spring-batch/issues/961),即使对我有用,它也不正确。

@Autowired
private JpaTransactionManager transactionManager;

private Step buildTaskletStep() {
        return stepBuilderFactory.get("SendCampaignStep")
                    .<UserAccount, UserAccount>chunk(pushServiceConfiguration.getCampaignBatchSize())
                    .reader(userAccountItemReader)
                    .processor(userAccountItemProcessor)
                    .writer(userAccountItemWriter)
                    .transactionManager(transactionManager)
                    .build();
    }
}

我尝试了实施 BatchConfigurer 的建议解决方案,但它与我使用此代码禁用元数据表冲突:

@Configuration
@EnableAutoConfiguration
@EnableBatchProcessing
public class BatchConfiguration extends DefaultBatchConfigurer {

    @Override
    public void setDataSource(DataSource dataSource) {
        // override to do not set datasource even if a datasource exist.
        // initialize will use a Map based JobRepository (instead of database)
    }

}

使用在步骤中设置 TransactionManager 的第一个解决方案会出现什么问题?

在Spring批处理中,有两个地方使用了事务管理器:

  • 在围绕 JobRepository 创建的代理中创建与作业存储库交互时的事务方法
  • 在每个步骤定义中驱动步骤的事务

通常,两个地方使用同一个事务管理器,但这不是必需的。将 ResourcelessTransactionManager 与作业存储库一起使用以不存储任何元数据,并在步骤中使用 JpaTransactionManager 将数据保存在数据库中是完全没问题的。

默认情况下,当您使用 @EnableBatchProcessing 并提供一个 DataSource bean 时,Spring Batch 将创建一个 DataSourceTransactionManager 并在两个地方设置它,因为这是最典型的案例。但是没有什么能阻止您为该步骤使用不同的事务管理器。在这种情况下,您应该接受业务数据和技术元数据在出现问题时可能会不同步的事实。

这就是为什么提供自定义事务管理器的预期方式是通过自定义 BatchConfigurer#getTransactionManager,在这种情况下,您的自定义事务管理器会在两个地方进行设置。这没有明确记录,但自 v4.1 以来已修复。这是提到的部分:Configuring a JobRepository. This is also mentioned in the Javadoc of @EnableBatchProcessing:

In order to use a custom transaction manager, a custom BatchConfigurer should be provided.