下面这篇建议作为下一篇发,标题简单一点:
MyBatis Invalid bound statement 怎么处理
它能承接你后面的 Spring Boot / MyBatis 报错方向,也比较适合吃长尾搜索词:
Invalid bound statement not found
MyBatis Invalid bound statement
Mapped Statements collection does not contain value
Mapper XML 找不到
MyBatis namespace 配置错误
mapper-locations 不生效
下面是可直接发布的正文。
MyBatis Invalid bound statement 怎么处理
最后更新:2026-07-31
适用场景:MyBatis、MyBatis-Plus、Spring Boot、Mapper XML、Invalid bound statement (not found)、Mapped Statements collection does not contain value
MyBatis 项目里比较常见的一个报错是:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
完整一点可能是:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
com.example.demo.mapper.UserMapper.selectById
这个报错翻译成人话就是:
MyBatis 找到了 UserMapper 接口,
但是没有找到 selectById 这个方法对应的 SQL 语句。
也就是说,Java 代码里调用了:
userMapper.selectById(1L);
但 MyBatis 在启动或运行时没有找到对应的 Mapper XML 语句。
这个问题通常不是数据库连不上,也不是 SQL 写错了,而是 Mapper 接口、Mapper XML、namespace、方法名、XML 加载路径 之间没对上。
MyBatis 本身支持通过 XML 或注解配置 SQL,并把 Java 对象映射到数据库记录;如果你使用 XML 方式,Mapper XML 里的 statement id、namespace 和 Java Mapper 接口之间的关系就很关键。(MyBatis)
一、先看结论
遇到这个报错,优先查这几件事:
1. Mapper XML 有没有被加载
2. XML 的 namespace 是否等于 Mapper 接口全限定名
3. XML 里的 select / insert / update / delete 的 id 是否等于接口方法名
4. mapper-locations 路径是否写对
5. XML 文件是否被打包进 target/classes
6. Mapper 接口是否被 Spring 扫描到
7. 多模块项目里 XML 是否在正确模块
8. MyBatis-Plus 项目里是否把自带 BaseMapper 方法和自定义 XML 搞混了
最常见的正确结构是:
Java接口:
com.example.demo.mapper.UserMapper
XML文件:
resources/mapper/UserMapper.xml
XML namespace:
com.example.demo.mapper.UserMapper
XML方法id:
selectUserById
接口方法:
selectUserById
对应示例:
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="selectUserById" resultType="com.example.demo.entity.User">
select * from user where id = #{id}
</select>
</mapper>
Java 接口:
public interface UserMapper {
User selectUserById(Long id);
}
只要 namespace + id 对不上,就容易报 Invalid bound statement。
二、这个错误到底是什么意思?
MyBatis 内部会把 XML 里的 SQL 语句注册成一个 mapped statement。
比如:
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="selectUserById">
select * from user where id = #{id}
</select>
</mapper>
它最终可以理解成注册了一个 statement:
com.example.demo.mapper.UserMapper.selectUserById
然后你调用:
userMapper.selectUserById(1L);
MyBatis 就去找:
com.example.demo.mapper.UserMapper.selectUserById
如果找不到,就报:
Invalid bound statement (not found)
MyBatis 官方 Mapper XML 文档也说明,select、insert、update、delete 等语句里的 id 是当前 namespace 中的唯一标识,用来引用对应 statement。(MyBatis)
所以这个错误的本质是:
Java Mapper 方法和 XML SQL statement 没绑定上。
三、先看报错里的完整方法名
报错里最有价值的是最后这一段:
com.example.demo.mapper.UserMapper.selectUserById
它告诉你 MyBatis 想找的是:
namespace = com.example.demo.mapper.UserMapper
id = selectUserById
所以第一步不要乱改配置,先去找对应的 XML。
你应该确认 XML 里是不是这样:
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="selectUserById">
...
</select>
</mapper>
如果 XML 里是:
<mapper namespace="com.example.demo.dao.UserMapper">
或者:
<select id="getUserById">
那就对不上。
四、原因一:namespace 写错
这是最常见原因之一。
Java 接口:
package com.example.demo.mapper;
public interface UserMapper {
User selectUserById(Long id);
}
XML 错误写法:
<mapper namespace="UserMapper">
或者:
<mapper namespace="com.example.demo.dao.UserMapper">
正确写法:
<mapper namespace="com.example.demo.mapper.UserMapper">
namespace 最稳的写法就是 Mapper 接口的完整包名 + 类名。
com.example.demo.mapper.UserMapper
不要只写:
UserMapper
也不要写错包名。
五、原因二:XML 里的 id 和接口方法名不一致
接口方法:
User selectUserById(Long id);
XML 错误写法:
<select id="getUserById" resultType="com.example.demo.entity.User">
select * from user where id = #{id}
</select>
MyBatis 找的是:
UserMapper.selectUserById
但 XML 里注册的是:
UserMapper.getUserById
肯定找不到。
正确写法:
<select id="selectUserById" resultType="com.example.demo.entity.User">
select * from user where id = #{id}
</select>
简单记:
Mapper接口方法名 = XML中的id
六、原因三:Mapper XML 没有被加载
有时候 namespace 和 id 都没错,但还是报错。
这时就要怀疑 XML 根本没有被 MyBatis 加载。
Spring Boot 项目里常见配置:
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
如果你的 XML 放在:
src/main/resources/mapper/UserMapper.xml
上面这个配置一般可以加载到。
如果 XML 放在:
src/main/resources/mybatis/mapper/UserMapper.xml
那就要改成:
mybatis:
mapper-locations: classpath*:mybatis/mapper/**/*.xml
如果路径写错,MyBatis 启动时可能不会直接报错,但运行到对应方法时就会报:
Invalid bound statement (not found)
MyBatis Spring Boot Starter 文档里提到,它默认会搜索标记了 @Mapper 的 Mapper 接口;如果要自定义扫描方式,可以使用 @MapperScan。但 XML 文件位置仍然需要通过对应的 mapper locations 配置让 MyBatis 能找到。(MyBatis)
七、classpath 和 classpath* 怎么选
常见写法:
mybatis:
mapper-locations: classpath:mapper/*.xml
或者:
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
我的建议是:
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
原因:
classpath: 通常只加载一个 classpath 位置
classpath*: 可以扫描多个 classpath 位置
**/*.xml 可以匹配多级目录
多模块项目、依赖 jar 里有 XML、Mapper 分散在不同目录时,classpath*: 更稳一些。
八、原因四:XML 文件没有打包进 target/classes
本地看着 XML 在项目里,但打包后不在 target/classes 里,也会找不到。
先检查:
target/classes/mapper/UserMapper.xml
如果没有这个文件,说明资源没有被打包进去。
正常 Maven 项目里,Mapper XML 推荐放在:
src/main/resources/mapper/UserMapper.xml
不要放在:
src/main/java/com/example/demo/mapper/UserMapper.xml
如果你一定要放在 src/main/java 下面,需要额外配置资源打包,但不建议这么做。
推荐结构:
src/main/java
└── com/example/demo/mapper/UserMapper.java
src/main/resources
└── mapper/UserMapper.xml
九、原因五:Mapper 接口没有被扫描到
Spring Boot 项目中 Mapper 接口通常有两种注册方式。
方式一:接口上加 @Mapper
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
User selectUserById(Long id);
}
方式二:启动类上加 @MapperScan
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.example.demo.mapper")
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
如果你没有给接口加 @Mapper,也没有配置 @MapperScan,Spring 可能根本没有注册 Mapper Bean。
MyBatis-Spring 文档中也说明,可以通过 <mybatis:scan/>、@MapperScan 或 MapperScannerConfigurer 自动扫描 Mapper 接口;这样就不需要一个个手动注册 Mapper。(MyBatis)
十、原因六:@MapperScan 扫描路径写错
启动类:
@MapperScan("com.example.demo.mapper")
@SpringBootApplication
public class DemoApplication {
}
如果你的 Mapper 实际在:
com.example.demo.modules.user.mapper
那就扫描不到。
可以改成更上层的包:
@MapperScan("com.example.demo")
或者准确写:
@MapperScan("com.example.demo.modules.user.mapper")
更推荐:
把 Mapper 接口统一放在明确目录里
例如:
com.example.demo.mapper
com.example.demo.module.user.mapper
不要散落在很多地方。
十一、原因七:XML 文件名和接口名不一致,会不会有问题?
严格来说,XML 文件名不一定非要和接口名一样。
比如接口是:
UserMapper.java
XML 文件叫:
UserSql.xml
只要 XML 被加载,并且 namespace 正确,id 正确,MyBatis 仍然能找到。
但实际项目里,强烈建议保持一致:
UserMapper.java
UserMapper.xml
这样排查时最直观,不容易出错。
十二、原因八:多模块项目路径没配对
多模块项目更容易出现这个问题。
例如项目结构:
demo-parent
├── demo-api
├── demo-service
└── demo-web
Mapper 接口在:
demo-service/src/main/java/com/example/mapper/UserMapper.java
XML 在:
demo-service/src/main/resources/mapper/UserMapper.xml
但启动类在:
demo-web
这时要确认:
demo-web 是否依赖 demo-service
demo-service 的 resources 是否打包进 jar
mapper-locations 是否能扫描到 demo-service 的 XML
@MapperScan 是否扫到 demo-service 的 mapper 包
多模块里建议使用:
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
不要只写:
mybatis:
mapper-locations: classpath:mapper/*.xml
十三、原因九:MyBatis-Plus 自带方法和自定义 XML 搞混
如果你用了 MyBatis-Plus:
public interface UserMapper extends BaseMapper<User> {
}
这种情况下,selectById、insert、updateById、deleteById 这些基础方法是 MyBatis-Plus 提供的,不需要你在 XML 里写。
但如果你写了自定义方法:
List<User> selectEnabledUsers();
那就需要在 XML 中写对应 SQL:
<select id="selectEnabledUsers" resultType="com.example.demo.entity.User">
select * from user where enabled = 1
</select>
也就是说:
BaseMapper自带方法:不需要XML
自定义Mapper方法:需要注解SQL或XML SQL
如果你只写了接口方法,没有写 XML,也没有注解 SQL,就会报:
Invalid bound statement
十四、原因十:XML 中 resultType 写错一般不是这个错误
有些人看到报错后会去改:
resultType
parameterType
但要分清楚。
如果错误是:
Invalid bound statement (not found)
优先查:
namespace
id
XML是否加载
Mapper是否扫描
resultType 写错更多会导致:
ClassNotFoundException
Result Maps collection does not contain value
字段映射失败
类型转换失败
不要一开始就把所有 XML 字段都改一遍。
十五、原因十一:注解方式和 XML 方式混用
MyBatis 支持注解和 XML 两种方式。
注解方式:
@Select("select * from user where id = #{id}")
User selectUserById(Long id);
XML 方式:
<select id="selectUserById" resultType="com.example.demo.entity.User">
select * from user where id = #{id}
</select>
两种方式可以用,但不要在项目里混得太乱。
我的建议:
简单SQL:可以用注解
复杂SQL:放到XML
团队项目:尽量统一风格
如果一个方法既没注解,也没 XML,就会找不到绑定语句。
十六、原因十二:XML 语法错误导致没有加载成功
有时候 XML 本身写错,比如:
<select id="selectUserById" resultType="com.example.demo.entity.User">
select * from user where id = #{id}
忘了闭合:
</select>
或者 XML 头、DOCTYPE、标签层级有问题。
这种通常启动时就会有 XML 解析报错。
如果日志很多,可能被你忽略了。
建议启动时搜索:
mapper
xml
Error parsing Mapper XML
BuilderException
SAXParseException
不要只看最后一行 Invalid bound statement。
十七、原因十三:target 里残留旧文件
本地开发时,有时改了 XML,但 target 里还是旧文件。
可以执行:
mvn clean
mvn package
或者直接:
mvn clean package
Gradle:
./gradlew clean build
IDEA 里也可以:
Build > Rebuild Project
如果你之前改过包名、改过 XML 路径、改过模块结构,建议先 clean 一次。
十八、推荐的 Spring Boot + MyBatis 配置
Maven 依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
如果你使用 Spring Boot 3,注意选择支持 Spring Boot 3 的 MyBatis Starter 版本。
application.yml
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.example.demo.entity
启动类
@MapperScan("com.example.demo.mapper")
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Mapper 接口
public interface UserMapper {
User selectUserById(Long id);
}
Mapper XML
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="selectUserById" resultType="com.example.demo.entity.User">
select id, username, nickname
from user
where id = #{id}
</select>
</mapper>
十九、怎么确认 XML 是否真的加载了
最直接的方式:看 target/classes。
例如:
target/classes/mapper/UserMapper.xml
如果没有,说明 XML 没被打包。
第二种方式:打开 debug 日志。
可以在 application.yml 中加:
logging:
level:
org.mybatis: debug
org.apache.ibatis: debug
也可以临时在 IDEA 控制台里观察启动日志,看是否有解析 Mapper XML 的记录。
第三种方式:故意把 XML 写错一点,看启动时是否报 XML 解析错误。
如果你把 XML 写错了,项目启动完全没反应,那八成是 XML 根本没加载到。
这个办法有点粗,但本地排查时很直观。
二十、常见错误示例
错误一:namespace 少了包名
错误:
<mapper namespace="UserMapper">
正确:
<mapper namespace="com.example.demo.mapper.UserMapper">
错误二:方法名和 id 不一致
接口:
User selectUserById(Long id);
错误 XML:
<select id="getUserById">
正确 XML:
<select id="selectUserById">
错误三:mapper-locations 路径不对
XML 实际路径:
src/main/resources/mapper/UserMapper.xml
错误配置:
mybatis:
mapper-locations: classpath*:mybatis/**/*.xml
正确配置:
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
错误四:XML 放在了 src/main/java
不推荐:
src/main/java/com/example/demo/mapper/UserMapper.xml
推荐:
src/main/resources/mapper/UserMapper.xml
错误五:Mapper 接口没有被扫描
错误:
@SpringBootApplication
public class DemoApplication {
}
但接口上没有 @Mapper,也没有 @MapperScan。
正确:
@MapperScan("com.example.demo.mapper")
@SpringBootApplication
public class DemoApplication {
}
或者每个接口加:
@Mapper
public interface UserMapper {
}
二十一、完整排查清单
遇到 Invalid bound statement (not found),按下面顺序查:
1. 看报错最后的方法全限定名
2. 确认 XML 的 namespace 是否完全一致
3. 确认 XML 的 id 是否等于接口方法名
4. 确认 Mapper XML 路径是否在 src/main/resources
5. 确认 mapper-locations 是否能扫描到 XML
6. 确认 target/classes 里是否有 XML
7. 确认 Mapper 接口是否被 @Mapper 或 @MapperScan 扫描
8. 多模块项目检查依赖和 classpath
9. MyBatis-Plus 检查是否是自定义方法没写 XML
10. 检查 XML 是否有语法错误
11. 执行 mvn clean package
12. IDEA 中 Rebuild Project
13. 开启 MyBatis debug 日志查看加载情况
二十二、常见问题 FAQ
1. Invalid bound statement 是数据库错误吗?
通常不是。它更多是 Mapper 接口和 Mapper XML 没绑定上。
数据库连接错误一般会报:
Communications link failure
Access denied
Unknown database
Connection refused
2. XML 文件名必须和 Mapper 接口名一样吗?
不是必须,但强烈建议一样。
UserMapper.java
UserMapper.xml
这样最容易维护。
3. namespace 必须写接口全限定名吗?
如果你用 Mapper 接口方式,建议写接口全限定名。
例如:
com.example.demo.mapper.UserMapper
4. id 必须和方法名一样吗?
是的,使用 XML 绑定 Mapper 接口方法时,XML 中的 id 要和接口方法名一致。
5. Mapper 接口一定要加 @Mapper 吗?
不一定。
你可以每个接口加 @Mapper,也可以在启动类上统一加:
@MapperScan("com.example.demo.mapper")
二选一即可。项目里我更推荐统一用 @MapperScan。
6. MyBatis-Plus 的 selectById 报这个错怎么办?
如果你继承了:
BaseMapper<User>
正常情况下 selectById 不需要 XML。
如果 selectById 也报错,优先检查:
实体类主键配置
Mapper是否继承BaseMapper
MyBatis-Plus版本是否正确
Mapper是否被扫描
是否混用了多个SqlSessionFactory
7. mapper-locations 写了还是不生效怎么办?
检查:
XML实际路径
target/classes里有没有XML
配置文件是否被当前profile加载
classpath和classpath*写法
多模块依赖是否正确
如果改了配置但没生效,先确认当前启动的 profile。
二十三、最后总结
Invalid bound statement (not found) 的核心意思是:
MyBatis 找不到当前 Mapper 方法对应的 SQL statement。
最常见原因就三个:
namespace 不对
id 不对
XML 没加载
排查时不要乱改一堆配置,先拿报错里的完整方法名去对 XML:
com.example.demo.mapper.UserMapper.selectUserById
然后确认:
namespace = com.example.demo.mapper.UserMapper
id = selectUserById
再检查:
mapper-locations
target/classes
@MapperScan
多模块资源路径
只要把这几项对齐,这个错误大多数都能解决。
二十四、相关文章
Spring Boot DataSource 报错:
Maven 依赖冲突:
Maven 国内镜像:
Spring Boot JDK 兼容:
Spring Boot 2 升级 3:
Java 开发环境配置专题:
更新记录
2026-07-31:
- 创建 MyBatis Invalid bound statement 排查文章
- 增加 namespace、id、mapper-locations、@MapperScan 排查说明
- 增加 Spring Boot + MyBatis 推荐配置
- 增加多模块项目、MyBatis-Plus、自定义 XML 方法等场景
- 增加完整排查清单和常见问题
MyBatis Invalid bound statement 怎么处理
https://java.li/archives/mybatis-invalid-bound-statement
评论