在 Spring Boot 项目中接入 MyBatis-Plus 时,很多人都会遇到下面这个异常:
org.apache.ibatis.binding.BindingException:
Invalid bound statement (not found): cn.xxx.xxxmapper.HaMapper.insert
表面看起来像是 Mapper 或 XML 没配置好,但如果你已经:
-
Mapper 能正常注入
-
XML 的
select能用 -
唯独
BaseMapper.insert()报错
👉 那 99% 是 SqlSessionFactoryBean 配置导致的。
本文通过一次真实踩坑经历,系统讲清楚:
-
问题产生的根因
-
为什么 MyBatis-Plus 特别容易中招
-
正确 & 官方推荐的解决方案
一、问题现象
异常信息如下:
Invalid bound statement (not found): cn.ha.xx.xxmapper.HaMapper.insert
对应代码:
haMapper.insert(entity);
而 HaMapper 定义如下:
public interface HaMapper extends BaseMapper<HaEntity> {
}
看起来完全没问题,但一运行就报错。
二、为什么 MyBatis-Plus 会在 insert 上报错?
1️⃣ BaseMapper 的 SQL 是「自动注入」的
这是关键背景。
-
insert / deleteById / updateById -
并不在 XML 中
-
而是在 SqlSessionFactory 初始化时
-
由 MyBatis-Plus 动态注册
这个注册过程 只会发生在:MybatisSqlSessionFactoryBean中。
2️⃣ 手动配置 SqlSessionFactoryBean 会发生什么?
很多项目(尤其是老项目 / 多数据源)都会写类似配置:
java
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
return factoryBean.getObject();
}
⚠️ 问题就在这里。
你虽然成功创建了 SqlSessionFactory,但:
-
❌ 绕开了 MyBatis-Plus 的自动配置
-
❌ BaseMapper 的 CRUD SQL 根本没有被注入
结果就是:
XML 里的 SQL 能用 BaseMapper.insert → Invalid bound statement
三、如何快速判断是不是这个坑?
你可以对照下面这个表:
| 现象 | 是否命中该问题 |
|---|---|
| Mapper 能注入 | ✅ |
| XML select 正常 | ✅ |
| BaseMapper.insert 报错 | ✅ |
| 项目中存在 SqlSessionFactoryBean | 100% 命中 |
如果你 手动 new 了 SqlSessionFactoryBean,几乎可以直接确认原因。
四、正确的解决方案(官方推荐)
✅ 方案一:删除自定义 SqlSessionFactory(最推荐)
如果你不是多数据源、也没有特别定制需求:
java
@Configuration
@MapperScan("cn.ha.xx.xxmapper")
public class MybatisPlusConfig {
}
只保留依赖:
XML
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
👉 MyBatis-Plus 会自动:
-
使用
MybatisSqlSessionFactoryBean -
注入 BaseMapper CRUD
-
扫描 Mapper
这是最稳妥、最不容易出问题的方式。
✅ 方案二:必须自定义时,用 MybatisSqlSessionFactoryBean
如果你确实需要手动配置(如插件、多数据源):
java
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:/mapper/**/*.xml")
);
return factory.getObject();
}
❗ 重点只有一句:
不要再使用
SqlSessionFactoryBean
✅ 方案三:多数据源场景(高频踩坑)
java
@Bean
@Primary
public SqlSessionFactory primarySqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
return factory.getObject();
}
配合:
java
@MapperScan(
basePackages = "cn.ha.xx.xxmapper",
sqlSessionFactoryRef = "primarySqlSessionFactory"
)
五、为什么这个坑特别隐蔽?
原因只有一个:
它不是配置错误,而是"配置覆盖成功了,但逻辑被绕开了"
-
不报 Bean 冲突
-
不报启动异常
-
直到你调用
BaseMapper.insert才炸
非常具有迷惑性。
六、总结
如果你在 MyBatis-Plus 中遇到:
Invalid bound statement (not found): xxxMapper.insert
请第一时间检查:
❗ 是否手动配置了 SqlSessionFactoryBean
记住一句话就够了:
👉 用 MyBatis-Plus,就要让它掌控 SqlSessionFactory