[英]Use of multiple DataSources in Spring Batch
I am trying to configure a couple of datasources within Spring Batch.我正在尝试在 Spring Batch 中配置几个数据源。 On startup, Spring Batch is throwing the following exception:
在启动时,Spring Batch 抛出以下异常:
To use the default BatchConfigurer the context must contain no more thanone DataSource, found 2
Snippet from Batch Configuration批处理配置的片段
@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
}
...
}
Not sure why I am seeing this exception, because I have seen some xml based configuration for Spring batch that declare multiple datasources.不知道为什么我会看到这个异常,因为我看到了一些声明多个数据源的 Spring 批处理的基于 xml 的配置。 I am using Spring Batch core version 3.0.1.RELEASE with Spring Boot version 1.1.5.RELEASE.
我正在使用 Spring Batch 核心版本 3.0.1.RELEASE 和 Spring Boot 版本 1.1.5.RELEASE。 Any help would be greatly appreciated.
任何帮助将不胜感激。
You must provide your own BatchConfigurer.您必须提供自己的 BatchConfigurer。 Spring does not want to make that decision for you
Spring 不想为你做那个决定
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Bean
BatchConfigurer configurer(@Qualifier("batchDataSource") DataSource dataSource){
return new DefaultBatchConfigurer(dataSource);
}
...
AbstractBatchConfiguration
tries to lookup BatchConfigurer
in container first, if it is not found then tries to create it itself - this is where IllegalStateException
is thrown where there is more than one DataSource
bean in container. AbstractBatchConfiguration
尝试首先在容器中查找BatchConfigurer
,如果找不到,则尝试自己创建它 - 这是在容器中有多个DataSource
bean 时抛出IllegalStateException
的地方。
The approach to solving the problem is to prevent from creation the DefaultBatchConfigurer
bean in AbstractBatchConfiguration
.解决问题的方法是防止在
AbstractBatchConfiguration
创建DefaultBatchConfigurer
bean。 To do it we hint to create DefaultBatchConfigurer
by Spring container using @Component
annotation:为此,我们提示使用
@Component
注释通过 Spring 容器创建DefaultBatchConfigurer
:
The configuration class where @EnableBatchProcessing
is placed we can annotate with @ComponentScan
that scan the package that contains the empty class that is derived from DefaultBatchConfigurer
:放置
@EnableBatchProcessing
的配置类我们可以使用@ComponentScan
进行注释,以扫描包含从DefaultBatchConfigurer
派生的空类的包:
package batch_config;
...
@EnableBatchProcessing
@ComponentScan(basePackageClasses = MyBatchConfigurer.class)
public class MyBatchConfig {
...
}
the full code of that empty derived class is here:该空派生类的完整代码在这里:
package batch_config.components;
import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
import org.springframework.stereotype.Component;
@Component
public class MyBatchConfigurer extends DefaultBatchConfigurer {
}
In this configuration the @Primary
annotation works for DataSource
bean as in the example below:在此配置中,
@Primary
注释适用于DataSource
bean,如下例所示:
@Configuration
public class BatchTestDatabaseConfig {
@Bean
@Primary
public DataSource dataSource()
{
return .........;
}
}
This works for the Spring Batch version 3.0.3.RELEASE这适用于 Spring Batch 版本 3.0.3.RELEASE
The simplest solution to make @Primary
annotation on DataSource
work might be just adding @ComponentScan(basePackageClasses = DefaultBatchConfigurer.class)
along with @EnableBatchProcessing
annotation:使
@Primary
注释在DataSource
工作的最简单的解决方案可能只是添加@ComponentScan(basePackageClasses = DefaultBatchConfigurer.class)
和@EnableBatchProcessing
注释:
@Configuration
@EnableBatchProcessing
@ComponentScan(basePackageClasses = DefaultBatchConfigurer.class)
public class MyBatchConfig {
I would like to provide a solution here, which is very similar to the one answered by @vanarchi, but I managed to put all the necessary configurations into one class.我想在这里提供一个解决方案,它与@vanarchi 的回答非常相似,但我设法将所有必要的配置放在一个类中。
For the sake of completeness, the solution here assumes that primary datasource is hsql.为了完整起见,这里的解决方案假设主数据源是 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", ""});
}
} }
THREE key points in this solution:此解决方案的三个关键点:
@EnableBatchProcessing
and @Configuration
, as well as extended from DefaultBatchConfigurer
.@EnableBatchProcessing
和@Configuration
注释,并从DefaultBatchConfigurer
扩展而来。 By doing this, we instruct spring-batch to use our customized batch configurer when AbstractBatchConfiguration
tries to lookup BatchConfigurer
;AbstractBatchConfiguration
尝试查找BatchConfigurer
时,我们指示 spring-batch 使用我们自定义的批处理配置器;@Primary
, which instruct spring-batch to use this datasource as its datasource of storing the 9 job related tables.@Primary
,指示 spring-batch 使用此数据源作为其存储 9 个作业相关表的数据源。protected JobRepository createJobRepository() throws Exception
method, which makes the jobRepository bean to use the primary datasource, as well as use a different transactionManager instance from the other datasource(s).protected JobRepository createJobRepository() throws Exception
方法,这使得 jobRepository bean 使用主数据源,并使用与其他数据源不同的 transactionManager 实例。The simplest solution is to extend the DefaultBatchConfigurer and autowire your datasource via a qualifier:最简单的解决方案是扩展 DefaultBatchConfigurer 并通过限定符自动装配您的数据源:
@Component
public class MyBatchConfigurer extends DefaultBatchConfigurer {
/**
* Initialize the BatchConfigurer to use the datasource of your choosing
* @param firstDataSource
*/
@Autowired
public MyBatchConfigurer(@Qualifier("firstDataSource") DataSource firstDataSource) {
super(firstDataSource);
}
}
Side Note (as this also deals with the use of multiple data sources): If you use autoconfig to run data initialization scripts, you may notice that it's not initializing on the datasource you'd expect.旁注(因为这也涉及使用多个数据源):如果您使用 autoconfig 运行数据初始化脚本,您可能会注意到它没有在您期望的数据源上进行初始化。 For that issue, take a look at this: https://github.com/spring-projects/spring-boot/issues/9528
对于那个问题,看看这个: https : //github.com/spring-projects/spring-boot/issues/9528
If I may add to the above question, the implications of having 2 transaction contexts one for each DS.如果我可以补充上述问题,那么每个 DS 有 2 个事务上下文的含义。 How to integrate the XA transaction with Batch step as we would need to ensure the TXN management at step level?
如何将 XA 事务与 Batch 步骤集成,因为我们需要确保步骤级别的 TXN 管理? Requirement is like in a batch step we need the following.
要求就像在批处理步骤中我们需要以下内容。
First, create a custom BatchConfigurer首先,创建一个自定义的 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 {
...
}
}
Then,然后,
@Configuration
@EnableBatchProcessing
@ComponentScan("package")
public class JobConfig {
// define job, step, ...
}
You can define below beans and make sure you application.properties file has entries needed for您可以定义下面的 bean 并确保您的 application.properties 文件具有所需的条目
@Configuration
@PropertySource("classpath:application.properties")
public class DataSourceConfig {
@Primary
@Bean(name = "abcDataSource")
@ConfigurationProperties(prefix = "abc.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "xyzDataSource")
@ConfigurationProperties(prefix = "xyz.datasource")
public DataSource xyzDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
}
application.properties应用程序属性
abc.datasource.jdbc-url=XXXXX
abc.datasource.username=XXXXX
abc.datasource.password=xxxxx
abc.datasource.driver-class-name=org.postgresql.Driver
...........
...........
...........
...........
Here you can refer: Spring Boot Configure and Use Two DataSources这里可以参考: Spring Boot 配置和使用两个数据源
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.