Использование нескольких источников данных в Spring Batch
Я пытаюсь настроить пару источников данных в Spring Batch. При запуске Spring Batch генерирует следующее исключение:
To use the default BatchConfigurer the context must contain no more thanone DataSource, found 2
Фрагмент из пакетной конфигурации
@Configuration
@EnableBatchProcessing
public class BatchJobConfiguration {
@Primary
@Bean(name = "baseDatasource")
public DataSource dataSource() {
// first datasource definition here
}
@Bean(name = "secondaryDataSource")
public DataSource dataSource2() {
// second datasource definition here
}
...
}
Не знаю, почему я вижу это исключение, потому что я видел некоторую конфигурацию на основе xml для пакета Spring, которая объявляет несколько источников данных. Я использую Spring Batch core version 3.0.1.RELEASE с Spring Boot version 1.1.5.RELEASE. Любая помощь будет принята с благодарностью.
Ответы
Ответ 1
AbstractBatchConfiguration
пытается искать BatchConfigurer
сначала в контейнере, если он не найден, он пытается создать его сам - вот где IllegalStateException
выбрано, где есть более одного DataSource
bean в контейнере.
Подход к решению проблемы состоит в том, чтобы предотвратить создание DefaultBatchConfigurer
bean в AbstractBatchConfiguration
.
Для этого мы хотим создать DefaultBatchConfigurer
с помощью контейнера Spring, используя @Component
аннотация:
Здесь размещен класс конфигурации, где @EnableBatchProcessing
мы можем аннотировать с помощью @ComponentScan
, которые сканируют пакет, содержащий пустой класс, полученный из DefaultBatchConfigurer
:
package batch_config;
...
@EnableBatchProcessing
@ComponentScan(basePackageClasses = MyBatchConfigurer.class)
public class MyBatchConfig {
...
}
полный код этого пустого производного класса находится здесь:
package batch_config.components;
import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
import org.springframework.stereotype.Component;
@Component
public class MyBatchConfigurer extends DefaultBatchConfigurer {
}
В этой конфигурации аннотация @Primary
работает для DataSource
bean, как в примере ниже:
@Configuration
public class BatchTestDatabaseConfig {
@Bean
@Primary
public DataSource dataSource()
{
return .........;
}
}
Это работает для Spring пакетной версии 3.0.3.RELEASE
Простейшим решением для аннотации @Primary
на DataSource
может быть просто добавление @ComponentScan(basePackageClasses = DefaultBatchConfigurer.class)
вместе с аннотацией @EnableBatchProcessing
:
@Configuration
@EnableBatchProcessing
@ComponentScan(basePackageClasses = DefaultBatchConfigurer.class)
public class MyBatchConfig {
Ответ 2
Вы должны предоставить свой собственный BatchConfigurer. Spring не хочет принимать решение для вас
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Bean
BatchConfigurer configurer(@Qualifier("batchDataSource") DataSource dataSource){
return new DefaultBatchConfigurer(dataSource);
}
...
Ответ 3
Сначала создайте пользовательский BatchConfigurer
@Configuration
@Component
public class TwoDataSourcesBatchConfigurer implements BatchConfigurer {
@Autowired
@Qualifier("dataSource1")
DataSource dataSource;
@Override
public JobExplorer getJobExplorer() throws Exception {
...
}
@Override
public JobLauncher getJobLauncher() throws Exception {
...
}
@Override
public JobRepository getJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
// use the autowired data source
factory.setDataSource(dataSource);
factory.setTransactionManager(getTransactionManager());
factory.afterPropertiesSet();
return factory.getObject();
}
@Override
public PlatformTransactionManager getTransactionManager() throws Exception {
...
}
}
Тогда
@Configuration
@EnableBatchProcessing
@ComponentScan("package")
public class JobConfig {
// define job, step, ...
}
Ответ 4
Если я могу добавить к вышеуказанному вопросу, последствия наличия двух контекстов транзакций по одному для каждого DS. Как интегрировать транзакцию XA с шагом пакетной обработки, поскольку нам необходимо обеспечить управление TXN на уровне шагов? Требование похоже на пакетный шаг, нам нужно следующее.
- прочитайте из DS 1 - jpaItemReader
- записать в DS2 - JPAItemwriter
- прочитайте с DS2 - JPAItemreader
- записать в Ds1 - JPAItemwriter
- Зафиксировать все txns
Шаг завершен.
Ответ 5
Я хотел бы предложить здесь решение, которое очень похоже на тот, на который ответил @vanarchi, но мне удалось установить все необходимые конфигурации в один класс.
Для полноты решения здесь предполагается, что основным источником данных является hsql.
@Configuration
@EnableBatchProcessing
public class BatchConfiguration extends DefaultBatchConfigurer {
@Bean
@Primary
public DataSource batchDataSource() {
// no need shutdown, EmbeddedDatabaseFactoryBean will take care of this
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase embeddedDatabase = builder
.addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql")
.addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql")
.setType(EmbeddedDatabaseType.HSQL) //.H2 or .DERBY
.build();
return embeddedDatabase;
}
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(batchDataSource());
factory.setTransactionManager(transactionManager());
factory.afterPropertiesSet();
return (JobRepository) factory.getObject();
}
private ResourcelessTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
//NOTE: the code below is just to provide developer an easy way to access the in-momery hsql datasource, as we configured it to the primary datasource to store batch job related data. Default username : sa, password : ''
@PostConstruct
public void getDbManager(){
DatabaseManagerSwing.main(
new String[] { "--url", "jdbc:hsqldb:mem:testdb", "--user", "sa", "--password", ""});
}
}
ТРЕХ ключевых точек в этом решении:
- Этот класс аннотируется с помощью
@EnableBatchProcessing
и @Configuration
, а также расширен от DefaultBatchConfigurer
. Поступая таким образом, мы инструктируем spring -batch использовать наш настраиваемый пакетный конфигуратор, когда AbstractBatchConfiguration
пытается найти BatchConfigurer
;
- Аннотировать batchDataSource bean как
@Primary
, который инструктирует spring -batch использовать этот источник данных как свой источник данных для хранения 9 связанных с работой таблиц.
- Переопределить метод
protected JobRepository createJobRepository() throws Exception
, который заставляет jobRepository bean использовать первичный источник данных, а также использовать другой экземпляр transactionManager из другого источника данных.