【问题标题】:How to configure transaction management for different read/write data sources in Spring BatchSpring Batch中如何为不同读写数据源配置事务管理
【发布时间】:2022-12-04 15:08:43
【问题描述】:

我们使用带有 2 个数据源的 Spring Batch:1 个用于读取(源数据库),1 个用于写入(目标数据库)。

Spring Batch 配置为使用 JobRepositoryJobExplorer 的目标数据源/事务管理器:

@EnableBatchProcessing(transactionManagerRef = "destinationTransactionManager", dataSourceRef = "destinationDataSource")

对于作业配置,JpaCursorItemReader被配置为使用属于源数据库的EntityManagerFactory(带有属于源数据库的PlatformTransactionManager)。

JpaItemWriter 配置为使用属于目标数据库的EntityManagerFactoryPlatformTransactionManager。这个 PlatformTransactionManager@EnableBatchProcessing 中使用的是同一个。

我们面向块的步骤使用属于目标数据库的 PlatformTransactionManager(与 @EnableBatchProcessing 中使用的相同)。

我的问题是:这是一个正确的设置吗(尤其是关于事务管理)?到目前为止,它没有给我们带来任何问题。我有点担心,因为读者端使用不同的数据源。

我的假设是这应该有效,因为块的 PlatformTransactionManager 与用于 JobRepositoryJpaItemWriter 的相同。所以我假设当出现故障时,回滚进度(在元数据表中)和写入的项目至少应该有效,因为它们使用相同的数据源和事务管理器。此外,JpaCursorItemReader 似乎没有事务意识。

我们的配置如下所示(稍作修改以省略领域语言):

@Configuration
@AllArgsConstructor
@EnableBatchProcessing(transactionManagerRef = "destinationTransactionManager", dataSourceRef = "destinationDataSource")
public class JobConfiguration {
    @Bean
    public JpaCursorItemReader<SourceEntity> sourceReader(
        @Qualifier("sourceEntityManagerFactory") final LocalContainerEntityManagerFactoryBean sourceEntityManagerFactory
    ) {
        return new JpaCursorItemReaderBuilder<SourceEntity>()
            .name("SourceEntity")
            .entityManagerFactory(Objects.requireNonNull(sourceEntityManagerFactory.getObject()))
            .queryString("from SourceEntity")
            .build();
    }

    @Bean
    public JpaItemWriter<DestinationEntity> destinationWriter(
        @Qualifier("destinationEntityManagerFactory")
        final LocalContainerEntityManagerFactoryBean destinationEntityManagerFactory
    ) {
        return new JpaItemWriterBuilder<DestinationEntity>()
            .entityManagerFactory(Objects.requireNonNull(destinationEntityManagerFactory.getObject()))
            .build();
    }

    @Bean
    public Step step(
        @Qualifier("sourceReader") final JpaCursorItemReader<SourceEntity> reader,
        @Qualifier("destinationWriter") final JpaItemWriter<DestinationEntity> writer,
        final CustomProcessor processor, // implementation omitted for brevity
        @Qualifier("destinationTransactionManager") final PlatformTransactionManager transactionManager,
        final JobRepository jobRepository
    ) {
        return new StepBuilder("step", jobRepository)
            .<SourceEntity, DestinationEntity>chunk(10, transactionManager)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
    }

    @Bean
    public Job job(final Step step,
                   final JobRepository jobRepository) {
        return new JobBuilder("job", jobRepository)
            .incrementer(new RunIdIncrementer())
            .flow(step)
            .end()
            .build();
    }
}

这按预期工作,但我想知道这是否是关于 tx 管理的正确设置。

【问题讨论】:

    标签: java spring-boot spring-batch


    【解决方案1】:

    对于这种配置(从不同的数据源读取/写入,或写入两个不同的事务资源),最大的风险是您的业务数据和技术元数据在发生故障时会不同步。

    您需要做的是使用 JtaTransactionManager 配置 Spring Batch,它协调同一步骤中涉及的所有事务资源的事务管理器。

    如果配置正确,Spring Batch 保证读取器、写入器和作业存储库交互在同一事务中执行,以便业务数据和技术元数据作为一个单元提交或回滚。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-25
      • 1970-01-01
      • 1970-01-01
      • 2014-12-01
      • 2016-06-16
      • 2010-12-30
      • 2011-07-11
      • 2015-03-06
      相关资源
      最近更新 更多