error
Mybatis-Plus ( abbreviation MP) yes mybatis An enhancement tool for , stay mybatis On the basis of that, we can only enhance it and not change it , Simplified development efficiency . In fact, it helps us package some simple curd Method , Can be called directly , There’s no need to rewrite these simple sql sentence , similar JPA like that .
A new project was created two days ago , The persistence framework uses mybatis, Simultaneous introduction mybatis-plus Do enhancement tools , After the project starts , Call the interface, but found error , A reminder of the error is as follows :
The wrong message is “ Invalid binding statement “, The wrong place is the operation sql Method of statement , I checked the answer from the Internet , This error is mainly due to the configuration problem of data source binding , So I feel the melon , Start from where you configure the data source .
Find cause
Because the project is to do read-write separation of multiple data sources , So I integrated the dynamic configuration of data sources into a class DataSourceConfig in , This is the code for this class :
@Configuration
@MapperScan(basePackages = "com.xjt.proxy.mapper", sqlSessionTemplateRef = "sqlTemplate")
public class DataSourceConfig {
/**
* Main library
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDb() {
return DruidDataSourceBuilder.create().build();
}
/**
* Slave Library
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDb() {
return DruidDataSourceBuilder.create().build();
}
/**
* Master slave dynamic configuration
*/
@Bean
public DynamicDataSource dynamicDb(@Qualifier("masterDb") DataSource masterDataSource,
@Autowired(required = false) @Qualifier("slaveDb") DataSource slaveDataSource) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DynamicDataSourceEnum.MASTER.getDataSourceName(), masterDataSource);
if (slaveDataSource != null) {
targetDataSources.put(DynamicDataSourceEnum.SLAVE.getDataSourceName(), slaveDataSource);
}
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
return dynamicDataSource;
}
@Bean
public SqlSessionFactory sessionFactory(@Qualifier("dynamicDb") DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Mapper.xml"));
bean.setDataSource(dynamicDataSource);
return bean.getObject();
}
@Bean
public SqlSessionTemplate sqlTemplate(@Qualifier("sessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean(name = "dataSourceTx")
public DataSourceTransactionManager dataSourceTx(@Qualifier("dynamicDb") DataSource dynamicDataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dynamicDataSource);
return dataSourceTransactionManager;
}
}
The content is not complicated , It is mainly the data source configuration mapping of the master-slave database , And the injection of data sources SqlSessionFactory In the object , If you are confused about this part of the code or read-write separation , You can read my previous article 《 Is it difficult to separate reading from writing ?springboot combination aop It’s simple 》
There is no objection to master-slave mapping data sources , Thinking about it, there should be something wrong with the injection step , And then I put my eyes on sessionFactory
On the way , This method mainly returns a SqlSessionFactory
object , The object is created by creating a new SqlSessionFactoryBean
Object and injected into the data source , The problem should be this SqlSessionFactoryBean Class , later , Jing Pingge ( The big guy next to me ) After the reminder , This should be replaced by mybatis-plus The other one in Bean Factory , be called MybatisSqlSessionFactoryBean, Open the source code of this class , We found that this class is a copy of SqlSessionFactoryBean, And it rewrites its own custom loading method buildSqlSessionFactory
,
Jump to the source code of the method , Found that one piece of code is more important , Without this step in the configuration, the injection will fail ,
changes
in other words , You also need to configure the source of the data mapper Scanning path of , In this way , The changes are more clear , It’s where the data source is injected SqlSessionFactoryBean Change to MybatisSqlSessionFactoryBean after , And configuration mapper The path of the file , That is the sessionFactory Method to the following code :
@Bean
public SqlSessionFactory sessionFactory(@Qualifier("dynamicDb") DataSource dynamicDataSource) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath*:mapper/*Mapper.xml"));
return sqlSessionFactoryBean.getObject();
}
thus , Start the project again and you can operate normally sql Statement .