Related Project address: Https://github.com/helloworlde/SpringBoot-DynamicDataSource
1. Org.apache.ibatis.binding.BindingException:Invalid bound statement (not found)
The problem was encountered after using the dynamic Data source, which was caused by the failure to find the *.xml
file, but in the configuration file
It is true that the related configuration was added because it was not set after setting SqlSessionFactoryBean
the typeAliasesPackage
data source.
and mapperLocations
property or property is invalid;
If you added it in the application's entry class @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
,
DataSourceConfigure
set the related property in the class:
@Bean @ConfigurationProperties"mybatis")
publicsqlSessionFactoryBean() {
new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
return sqlSessionFactoryBean;
}
or direct configuration (this is not recommended):
@Bean
public sqlsessionfactorybean Sqlsessionfactorybean () {
Sqlsessionfactorybean Sqlsessionfactorybean = new
Sqlsessionfactorybean ();
Sqlsessionfactorybean.settypealiasespackage ( "typealiasespackage" );
Sqlsessionfactorybean.setmapperlocations (new Pathmatchingresourcepatternresolver (). Getresources ( "mapperlocations" ));
Sqlsessionfactorybean.setdatasource (Dynamicdatasource ());
return Sqlsessionfactorybean;
}
2. Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to I Dentify The bean that should is consumed
The exception is clearly stated in the error message because there are multiple DataSource
instances, so it is not possible to determine the reference to that instance
To add an annotation to a data source Bean
@Primary
, it Bean
should be DataSourceBuilder.create().build()
The resulting Bean
, rather than new AbstractRoutingDataSource
the subclass of the implementation Bean
, in this project can be master()
Or slave()
get DataSource
, can't be dynamicDataSource()
got.DataSource
3. Dynamic switch data source is invalid by annotation mode
- Make sure that the annotations are not placed on the DAO layer method because transactions are turned on at the service layer, so the annotations do not take effect when they are in the DAO layer
- Please confirm the following
Bean
correct configuration:
@Bean("Dynamicdatasource")
PublicDataSourceDynamicdatasource() {
Dynamicroutingdatasource Dynamicroutingdatasource =NewDynamicroutingdatasource ();
Map<object, object> datasourcemap =NewHashmap<> (2);
Datasourcemap.put ("Master", master ());
Datasourcemap.put ("Slave", slave ());
//Set master DataSource as default
Dynamicroutingdatasource.setdefaulttargetdatasource (Master ());
//Set master and slave datasource as target datasource
Dynamicroutingdatasource.settargetdatasources (DATASOURCEMAP);
//To put DataSource keys into Datasourcecontextholder to judge if the DataSource is exist
DynamicDataSourceContextHolder.dataSourceKeys.addAll (Datasourcemap.keyset ());
}
returnDynamicroutingdatasource;
}
@Bean
@ConfigurationProperties(prefix ="MyBatis")
PublicSqlsessionfactorybeanSqlsessionfactorybean() {
Sqlsessionfactorybean Sqlsessionfactorybean =NewSqlsessionfactorybean ();
//Here's very important, if don ' t config this, would can ' t switch datasource
//Put all DataSource to Sqlsessionfactorybean, then'll autoconfig sqlsessionfactory
Sqlsessionfactorybean.setdatasource (Dynamicdatasource ());
returnSqlsessionfactorybean;
}
4.
@Transactional
invalid annotation, exception not rolled back
- Verify that it is
Bean
properly configured and @Transactional
rollbackFor
configured correctly
@Bean
publictransactionManager() {
returnnew DataSourceTransactionManager(dynamicDataSource());
}
5. Invalid switch data source when DAO layer method name is judged by AOP
After the slice points to the DAO layer, regardless of the order in which the slices are set, the data source cannot be toggled before the query is executed, but the slice changes to the Service layer and works correctly
Workaround: Make sure that the @Transactional
annotations are added to the method instead of the service class, @Transactional
because transactions are turned on in the service layer.
The data source will not be switched until after the transaction has ended
Check out DataSourceTransactionManager
beans injected correctly
@Bean
publictransactionManager() {
returnnew DataSourceTransactionManager(dynamicDataSource());
}
6. The dependencies of some of the beans in the application context form a cycle
The dependencies of some of the beansinchThe application context form a cycle:
Producecontroller (Field private CN. com. Hellowood. Dynamicdatasource. Service. Productservicecn. com. Hellowood. Dynamicdatasource. Controller. Producecontroller. Productservice)
↓
Productservice (Field private CN. com. Hellowood. Dynamicdatasource. Mapper. Productdaocn. com. Hellowood. Dynamicdatasource. Service. Productservice. Productdao)
↓
Productdao definedinchfile [/users/hehuimin/downloads/dev/springboot/dynamicdatasource/ out/production/classes/cn/com/hellowood/dynamicdatasource/mapper/productdao. Class]
↓
Sqlsessionfactorybean definedinchClass path Resource [cn/com/hellowood/dynamicdatasource/configuration/datasourceconfigurer. Class]
┌─────┐
| Dynamicdatasource definedinchClass path Resource [cn/com/hellowood/dynamicdatasource/configuration/datasourceconfigurer. Class]
↑
↓
| Master definedinchClass path Resource [cn/com/hellowood/dynamicdatasource/configuration/datasourceconfigurer. Class]
↑
↓
| Datasourceinitializer
└─────┘
This is because the injected DataSource
instance produces a cyclic call, and the first injected bean relies on the other bean, and the dependent bean generates a dependency pass, relying on the first
Injected beans, caught in a loop, unable to start the project
- Workaround: Point the
@Primary
annotation to a Bean that is not dependent, such as:
/**
* Master DataSource
* @Primary annotations are used to identify the DataSource bean that is used by default because there are three DataSource beans that can be used with the master
* or slave DataSource bean, but not for dynamicdatasource bean, otherwise it will produce a cyclic call
* * @ConfigurationProperties annotations are used to read the configuration from the Application.properties file and to set properties for the Bean
* @return Data source
*/
@Bean("Master")
@Primary
@ConfigurationProperties(prefix ="Application.server.db.master")
PublicDataSourceMaster() {
returnDatasourcebuilder.create (). build ();
}@Bean("Slave")
@ConfigurationProperties(prefix ="Application.server.db.slave")
PublicDataSourceslave() {
returnDatasourcebuilder.create (). build ();
}@Bean("Dynamicdatasource")
PublicDataSourceDynamicdatasource() {
Dynamicroutingdatasource Dynamicroutingdatasource =NewDynamicroutingdatasource ();
Map<object, object> datasourcemap =NewHashmap<> (2);
Datasourcemap.put ("Master", master ());
Datasourcemap.put ("Slave", slave ());
//Set master DataSource as default
Dynamicroutingdatasource.setdefaulttargetdatasource (Master ());
//Set master and slave datasource as target datasource
Dynamicroutingdatasource.settargetdatasources (DATASOURCEMAP);
//To put DataSource keys into Datasourcecontextholder to judge if the DataSource is exist
DynamicDataSourceContextHolder.dataSourceKeys.addAll (Datasourcemap.keyset ());
returnDynamicroutingdatasource;
}
Issues and workarounds for dynamically switching data sources using Spring Boot and MyBatis