gpt4 book ai didi

spring-boot-starter-jta-atomikos 和 spring-boot-starter-batch

转载 作者:行者123 更新时间:2023-12-03 09:03:15 27 4
gpt4 key购买 nike

是否可以在一个应用程序中同时使用这两个启动器?

我想将 CSV 文件中的记录加载到数据库表中。 Spring Batch 表存储在不同的数据库中,因此我假设我需要使用 JTA 来处理事务。

每当我将 @EnableBatchProcessing 添加到我的 @Configuration 类时,它都会配置一个 PlatformTransactionManager,这会阻止 Atomikos 自动配置它。

是否有任何 spring boot + batch + jta 示例展示了如何执行此操作?

非常感谢,詹姆斯

最佳答案

我刚刚经历了这个,我发现了一些似乎有效的东西。正如您所注意到的,@EnableBatchProcessing 会导致创建一个 DataSourceTransactionManager,这会弄乱一切。我在 @EnableBatchProcessing 中使用 modular=true,所以 ModularBatchConfiguration 类被激活。

我所做的是停止使用 @EnableBatchProcessing,而是将整个 ModularBatchConfiguration 类复制到我的项目中。然后我注释掉了 transactionManager() 方法,因为 Atomikos 配置创建了 JtaTransactionManager。我还必须覆盖 jobRepository() 方法,因为它被硬编码为使用在 DefaultBatchConfiguration 中创建的 DataSourceTransactionManager

我还必须显式导入 JtaAutoConfiguration 类。这会正确连接所有内容(根据 Actuator 的“beans”端点 - 感谢上帝)。但是当你运行它时,事务管理器会抛出一个异常,因为某处某处设置了一个显式的事务隔离级别。所以我也写了一个BeanPostProcessor来找到事务管理器并调用txnMgr.setAllowCustomIsolationLevels(true);

现在一切正常,但是当作业正在运行时,我无法使用 JdbcTemplate 从 batch_step_execution 表中获取当前数据,即使我可以在 SQLYog 中看到数据。这一定和事务隔离有关,但我还没有弄明白。

这是我的配置类,从 Spring 复制并按上述修改。 PS,我有我的 DataSource,它指向批处理表注释为 @Primary 的数据库。此外,我将 DataSource bean 更改为 org.apache.tomcat.jdbc.pool.XADataSource 的实例;我不确定是否有必要。

@Configuration
@Import(ScopeConfiguration.class)
public class ModularJtaBatchConfiguration implements ImportAware
{
@Autowired(required = false)
private Collection<DataSource> dataSources;

private BatchConfigurer configurer;

@Autowired
private ApplicationContext context;

@Autowired(required = false)
private Collection<BatchConfigurer> configurers;

private AutomaticJobRegistrar registrar = new AutomaticJobRegistrar();

@Bean
public JobRepository jobRepository(DataSource batchDataSource, JtaTransactionManager jtaTransactionManager) throws Exception
{
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(batchDataSource);
factory.setTransactionManager(jtaTransactionManager);
factory.afterPropertiesSet();
return factory.getObject();
}

@Bean
public JobLauncher jobLauncher() throws Exception {
return getConfigurer(configurers).getJobLauncher();
}

// @Bean
// public PlatformTransactionManager transactionManager() throws Exception {
// return getConfigurer(configurers).getTransactionManager();
// }

@Bean
public JobExplorer jobExplorer() throws Exception {
return getConfigurer(configurers).getJobExplorer();
}

@Bean
public AutomaticJobRegistrar jobRegistrar() throws Exception {
registrar.setJobLoader(new DefaultJobLoader(jobRegistry()));
for (ApplicationContextFactory factory : context.getBeansOfType(ApplicationContextFactory.class).values()) {
registrar.addApplicationContextFactory(factory);
}
return registrar;
}

@Bean
public JobBuilderFactory jobBuilders(JobRepository jobRepository) throws Exception {
return new JobBuilderFactory(jobRepository);
}

@Bean
// hopefully this will autowire the Atomikos JTA txn manager
public StepBuilderFactory stepBuilders(JobRepository jobRepository, JtaTransactionManager ptm) throws Exception {
return new StepBuilderFactory(jobRepository, ptm);
}

@Bean
public JobRegistry jobRegistry() throws Exception {
return new MapJobRegistry();
}

@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
AnnotationAttributes enabled = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(
EnableBatchProcessing.class.getName(), false));
Assert.notNull(enabled,
"@EnableBatchProcessing is not present on importing class " + importMetadata.getClassName());
}

protected BatchConfigurer getConfigurer(Collection<BatchConfigurer> configurers) throws Exception {
if (this.configurer != null) {
return this.configurer;
}
if (configurers == null || configurers.isEmpty()) {
if (dataSources == null || dataSources.isEmpty()) {
throw new UnsupportedOperationException("You are screwed");
} else if(dataSources != null && dataSources.size() == 1) {
DataSource dataSource = dataSources.iterator().next();
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(dataSource);
configurer.initialize();
this.configurer = configurer;
return configurer;
} else {
throw new IllegalStateException("To use the default BatchConfigurer the context must contain no more than" +
"one DataSource, found " + dataSources.size());
}
}
if (configurers.size() > 1) {
throw new IllegalStateException(
"To use a custom BatchConfigurer the context must contain precisely one, found "
+ configurers.size());
}
this.configurer = configurers.iterator().next();
return this.configurer;
}

}

@Configuration
class ScopeConfiguration {

private StepScope stepScope = new StepScope();

private JobScope jobScope = new JobScope();

@Bean
public StepScope stepScope() {
stepScope.setAutoProxy(false);
return stepScope;
}

@Bean
public JobScope jobScope() {
jobScope.setAutoProxy(false);
return jobScope;
}

}

关于spring-boot-starter-jta-atomikos 和 spring-boot-starter-batch,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29921177/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com