The project is hosted on GitHub: y0ngb1n/spring-boot-samples, feel free to Star, Fork 😘
Notes#
Configurations for different data sources should be separated
In Spring, we need to separate the configurations for two different data sources. For example, if we have a foo-datasource
and another bar-datasource
, all configurations for these two DataSources should be kept separate. Even if their configurations are the same except for the url
, it is recommended to configure them separately for easier management in the future.
Pay attention to the data source being used each time
- How does the system determine which DataSource to use when there are multiple DataSources?
- How do the corresponding facilities (transactions, ORM, etc.) select the DataSource?
When programming, we must pay special attention to which data source we are currently operating on, and inform our system which DataSource to use. Transaction management should be enabled on the appropriate DataSource; at the same time, we also need to inform the relevant ORM (like Hibernate, MyBatis, etc.) which DataSource is being operated on, as these frameworks do not consider this thoroughly for us, so we must be extra careful during coding.
Multiple Data Source Configuration#
Manually configure two sets of DataSource and related content
If we rely entirely on manual configuration, excluding all Spring Boot-related dependencies, it is certainly possible to configure everything ourselves.
If you still want to integrate with Spring Boot, you can refer to the following two methods.
Working with Spring Boot (choose one)
- Method 1: Configure
@Primary
type Bean - Method 2: Exclude Spring Boot's auto-configuration
DataSourceAutoConfiguration
DataSourceTransactionManagerAutoConfiguration
JdbcTemplateAutoConfiguration
Method 1: Spring will treat the Bean configured with @Primary
as the primary Bean, and all subsequent Spring Boot-related auto-configuration will revolve around this @Primary
marked DataSource.
Method 2: If you believe that these two Beans are equally important and there is no primary or secondary distinction, we can exclude the Beans listed in Method 2. After excluding them, we can control them ourselves in the code, as shown in the following code:
Step 01: Exclude Spring Boot's auto-configuration
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class
})
public class MultiDataSourceApplication {
public static void main(String[] args) {
SpringApplication.run(MultiDataSourceApplication.class, args);
}
}
Step 02: Add foo
and bar
data source configurations
# Foo DataSource
foo:
datasource:
url: jdbc:h2:mem:foo
username: sa
password:
# Bar DataSource
bar:
datasource:
url: jdbc:h2:mem:bar
username: sa
password:
Step 03: Add configurations for foo-datasource
and bar-datasource
, along with the corresponding transaction managers
@Slf4j
@Configuration
public class MultiDataSourceConfig {
//---------------------------------------------------------------------
// Config Foo DataSource
//---------------------------------------------------------------------
@Bean
@ConfigurationProperties("foo.datasource")
public DataSourceProperties fooDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
public DataSource fooDataSource() {
DataSourceProperties dataSourceProperties = fooDataSourceProperties();
log.info("foo datasource: {}", dataSourceProperties.getUrl());
return dataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean
@Resource
public PlatformTransactionManager fooTxManager(DataSource fooDataSource) {
return new DataSourceTransactionManager(fooDataSource);
}
//---------------------------------------------------------------------
// Config Bar DataSource
//---------------------------------------------------------------------
@Bean
@ConfigurationProperties("bar.datasource")
public DataSourceProperties barDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
public DataSource barDataSource() {
DataSourceProperties dataSourceProperties = barDataSourceProperties();
log.info("bar datasource: {}", dataSourceProperties.getUrl());
return dataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean
@Resource
public PlatformTransactionManager barTxManager(DataSource barDataSource) {
return new DataSourceTransactionManager(barDataSource);
}
}
Step 04: Verify if the configuration is successful
$ mvn spring-boot:run
...
2019-09-18 23:57:21.649 INFO 15826 --- [ main] i.g.y.s.m.config.MultiDataSourceConfig : foo datasource: jdbc:h2:mem:foo
2019-09-18 23:57:21.708 INFO 15826 --- [ main] i.g.y.s.m.config.MultiDataSourceConfig : bar datasource: jdbc:h2:mem:bar
...
$ curl -s http://localhost:8080/actuator/beans | jq
{
"contexts": {
"application": {
"beans": {
...
"fooDataSourceProperties": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.boot.autoconfigure.jdbc.DataSourceProperties",
"resource": "class path resource [io/github/y0ngb1n/samples/multidatasource/config/MultiDataSourceConfig.class]",
"dependencies": []
},
"fooDataSource": {
"aliases": [],
"scope": "singleton",
"type": "com.zaxxer.hikari.HikariDataSource",
"resource": "class path resource [io/github/y0ngb1n/samples/multidatasource/config/MultiDataSourceConfig.class]",
"dependencies": [
"fooDataSourceProperties"
]
},
"fooTxManager": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.jdbc.datasource.DataSourceTransactionManager",
"resource": "class path resource [io/github/y0ngb1n/samples/multidatasource/config/MultiDataSourceConfig.class]",
"dependencies": [
"fooDataSource"
]
},
...
"barDataSourceProperties": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.boot.autoconfigure.jdbc.DataSourceProperties",
"resource": "class path resource [io/github/y0ngb1n/samples/multidatasource/config/MultiDataSourceConfig.class]",
"dependencies": []
},
"barDataSource": {
"aliases": [],
"scope": "singleton",
"type": "com.zaxxer.hikari.HikariDataSource",
"resource": "class path resource [io/github/y0ngb1n/samples/multidatasource/config/MultiDataSourceConfig.class]",
"dependencies": [
"barDataSourceProperties"
]
},
"barTxManager": {
"aliases": [],
"scope": "singleton",
"type": "org.springframework.jdbc.datasource.DataSourceTransactionManager",
"resource": "class path resource [io/github/y0ngb1n/samples/multidatasource/config/MultiDataSourceConfig.class]",
"dependencies": [
"barDataSource"
]
},
...
"multiDataSourceConfig": {
"aliases": [],
"scope": "singleton",
"type": "io.github.y0ngb1n.samples.multidatasource.config.MultiDataSourceConfig$$EnhancerBySpringCGLIB$$63c24bed",
"resource": "file [/Users/yangbin/workspace/coding/Java/spring-boot-samples/spring-boot-samples-multi-datasource/target/classes/io/github/y0ngb1n/samples/multidatasource/config/MultiDataSourceConfig.class]",
"dependencies": []
},
...
},
"parentId": null
}
}
}
You can view the dependency relationships of each Bean in Spring above.
This completes the configuration of multiple data sources in Spring Boot. If we have more data sources, the configuration will be similar; just refer to the above configuration.