我只是通過這個去了,我發現的東西,似乎工作。正如您所注意到的,@EnableBatchProcessing
會導致創建DataSourceTransactionManager
,這會混淆一切。我在@EnableBatchProcessing
中使用了modular = true,所以ModularBatchConfiguration
類被激活。
我所做的就是停止使用@EnableBatchProcessing
,而是將整個ModularBatchConfiguration
類複製到我的項目中。然後我註釋掉了transactionManager()
方法,因爲Atomikos配置創建了JtaTransactionManager
。我也不得不重寫jobRepository()
方法,因爲它被硬編碼爲使用在DefaultBatchConfiguration
內創建的DataSourceTransactionManager
。我也不得不明確導入JtaAutoConfiguration
類。這將電線正確連接(根據執行器的「豆」端點 - 感謝上帝)。但是當你運行它時,事務管理器會拋出一個異常,因爲某處某處設置了明確的事務隔離級別。所以我也寫了一個BeanPostProcesso
r找到交易管理器並打電話給txnMgr.setAllowCustomIsolationLevels(true)
;
現在一切正常,但作業正在運行時,即使我能看到SQLYog中的數據,我也無法使用JdbcTemplate
從batch_step_execution表中獲取當前數據。這必須與事務隔離有關,但我還沒有能夠理解它。
這是我的配置類,從Spring複製並修改如上所述。 PS,我有我的DataSource
指向批註表註釋爲@Primary
的數據庫。此外,我將我的DataSource
豆類更改爲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;
}
}
最後,即使這並沒有爲我工作。如果沒有讓Atomikos JTA Txn Mgr瘋狂並鎖定並殺死我所有的工作,我無法查詢數據庫。然後我意識到我的第二個數據源只讀取一個作業,所以我將所有配置恢復爲標準的非JTA配置,完全取出Atomikos,並創建了第二個只讀數據源作爲Tomcat DataSource池bean,其中autoCommit =只有在特定工作啓動時纔是真實的。 –