标题:解决 MyBatis-Plus 多数据源配置中 invalid bound statement not found 的问题
一、环境说明
当前项目使用的依赖版本如下:
xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!-- 并未引入 mybatis-plus 官方的多数据源依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.7</version>
</dependency>
二、多数据源的具体配置
启动类中的 @MapperScan
配置
java
@MapperScans({
@MapperScan(basePackages = {"com.aaa.dao"}, sqlSessionFactoryRef = DatasourceConf.SESSION_FACTORY),
@MapperScan(basePackages = {"com.bbb.dao"}, sqlSessionFactoryRef = OtherDatasourceConf.OTHER_SESSION_FACTORY)
})
主数据源配置类
java
@Configuration
public class DatasourceConf {
public static final String SESSION_FACTORY = "SessionFactory";
@Primary
@Bean(name = SESSION_FACTORY)
public SqlSessionFactory dianOrderSessionFactory(MybatisProperties properties) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(secondDatasource());
//...
}
@Primary
@Bean
public DataSource secondDatasource() {
return new HikariDataSource(secondHikariConfig());
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.aaa.hikari")
public HikariConfig secondHikariConfig() {
return new HikariConfig();
}
}
其他数据源配置类
java
@Configuration
public class OtherDatasourceConf {
public static final String OTHER_SESSION_FACTORY = "otherSessionFactory";
@Bean(name = OTHER_SESSION_FACTORY)
public SqlSessionFactory otherSessionFactory(MybatisProperties properties) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(otherDataSource());
//....
}
@Bean
public DataSource otherDataSource() {
return new HikariDataSource(otherHikariConfig());
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariConfig otherHikariConfig() {
return new HikariConfig();
}
}
三、问题描述
多数据源配置完成后,发现 基于 XML 配置的 SQL 执行正常。但是如果调用 MyBatis-Plus 提供的 内置方法(如 selectById
,updateById
等),会抛出如下异常:
txt
Invalid bound statement (not found)
四、原因分析
通过源码分析发现,MyBatis-Plus 默认会通过 MybatisPlusAutoConfiguration
自动配置 SqlSessionFactoryBean
,如下:
java
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisPlusAutoConfiguration implements InitializingBean {
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// 注意这里使用的是 MybatisSqlSessionFactoryBean 而非 SqlSessionFactoryBean
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
//...
return factory.getObject();
}
}
问题在于:多数据源的配置中,每个数据源需要手动配置 SqlSessionFactory
,直接导致 MybatisPlusAutoConfiguration
中的自动配置 SqlSessionFactory
无法生效。手动配置的 SqlSessionFactoryBean
为 MyBatis 的标准实现,而非 MyBatis-Plus 的 MybatisSqlSessionFactoryBean
,因此无法加载 MyBatis-Plus 的基础功能,导致出现了 Invalid bound statement
异常。
五、解决方案
为了解决上述问题,需要在多数据源配置类中,将标准 SqlSessionFactoryBean
修改为 Mybatis-Plus 提供的 MybatisSqlSessionFactoryBean
,并确保使用的是 MybatisPlusProperties
,而非 MybatisProperties
。以下是修正后的代码:
修改主数据源配置类
java
@Configuration
public class DatasourceConf {
public static final String SESSION_FACTORY = "SessionFactory";
@Primary
@Bean(name = SESSION_FACTORY)
public SqlSessionFactory dianOrderSessionFactory(MybatisPlusProperties properties) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean(); // 使用 MybatisSqlSessionFactoryBean
sqlSessionFactoryBean.setDataSource(secondDatasource());
sqlSessionFactoryBean.setConfiguration(properties.getConfiguration());
sqlSessionFactoryBean.setMapperLocations(properties.resolveMapperLocations());
//...
return sqlSessionFactoryBean.getObject();
}
@Primary
@Bean
public DataSource secondDatasource() {
return new HikariDataSource(secondHikariConfig());
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.aaa.hikari")
public HikariConfig secondHikariConfig() {
return new HikariConfig();
}
}
修改其他数据源配置类
java
@Configuration
public class OtherDatasourceConf {
public static final String OTHER_SESSION_FACTORY = "otherSessionFactory";
@Bean(name = OTHER_SESSION_FACTORY)
public SqlSessionFactory otherSessionFactory(MybatisPlusProperties properties) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean(); // 使用 MybatisSqlSessionFactoryBean
sqlSessionFactoryBean.setDataSource(otherDataSource());
sqlSessionFactoryBean.setConfiguration(properties.getConfiguration());
sqlSessionFactoryBean.setMapperLocations(properties.resolveMapperLocations());
//...
return sqlSessionFactoryBean.getObject();
}
@Bean
public DataSource otherDataSource() {
return new HikariDataSource(otherHikariConfig());
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariConfig otherHikariConfig() {
return new HikariConfig();
}
}
六、注意事项
-
MybatisSqlSessionFactoryBean
- MyBatis-Plus 针对 MyBatis 扩展的
SqlSessionFactoryBean
,负责加载内置基础方法及增强功能。
- MyBatis-Plus 针对 MyBatis 扩展的
-
MybatisPlusProperties
- 确保数据源配置中注入的属性来源为
MybatisPlusProperties
,这样可以正确加载 MyBatis-Plus 的 Mapper 配置。
- 确保数据源配置中注入的属性来源为
-
MapperScan
配置- 多数据源的 Mapper 需要通过
@MapperScan
注解,指定对应的SqlSessionFactory
。
- 多数据源的 Mapper 需要通过
七、小结
通过将标准 SqlSessionFactoryBean
替换为 MyBatis-Plus 的 MybatisSqlSessionFactoryBean
,并正确加载 MybatisPlusProperties
,可以成功解决多数据源场景下 invalid bound statement (not found) 的问题。如果你在实际操作中遇到更多问题,可以随时留言交流!