错误:Invalid bound statement (not found) 详解与解决方案
一、错误现象
运行测试时抛出:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xie.mapper.CarMapper.selectAllCar
二、错误含义
这个错误表示 MyBatis 已经识别到了 CarMapper 接口(已注册到 MapperRegistry),但在尝试执行 selectAllCar() 方法时,找不到对应的 SQL 映射语句。
换句话说:接口找到了,但接口方法 selectAllCar 没有在 XML 映射文件(或注解)中找到对应的 <select> 标签。
与之前的错误不同,之前是接口本身未被注册,现在是接口与 SQL 语句之间的绑定失败。
三、常见原因排查清单
| 原因 | 说明 |
|---|---|
1. XML 中的 <select> 标签的 id 与接口方法名不一致 |
最常见错误,例如 XML 写的是 selectAllCar,接口写的是 findAll,或者大小写不一致。 |
2. XML 的 namespace 与接口的全限定名不匹配 |
必须严格一致,例如 namespace="com.xie.mapper.CarMapper"。 |
| 3. XML 文件内容存在语法错误(如未闭合标签),导致解析失败 | 此时整个 XML 被跳过,所有语句都找不到。 |
4. XML 文件未被正确加载(例如 resource 路径错误,或编译后未复制到 target/classes) |
即使接口注册了,但 XML 没加载,也会导致绑不定。 |
5. 方法返回类型与 XML 中的 resultType 或 resultMap 不兼容 |
虽然通常不会导致"not found",但会报其他错误,但这里明确是 not found。 |
四、快速定位步骤
Step 1:检查接口方法名与 XML 的 id
- 接口 :
CarMapper.java
java
List<Car> selectAllCar();
- XML :
CarMapper.xml
xml
<select id="selectAllCar" resultType="com.xie.entity.Car">
SELECT * FROM t_car
</select>
确保两个地方的 selectAllCar 完全一致(包括大小写)。
Step 2:验证 XML 的 namespace
xml
<mapper namespace="com.xie.mapper.CarMapper">
必须与接口的全限定名完全一致。
Step 3:确认 XML 是否被正确解析
在 mybatis-config.xml 中开启日志(你已经开启了 STDOUT_LOGGING),启动时 MyBatis 会打印加载的 Mapper 信息。观察控制台是否有类似:
Registered mapper: com.xie.mapper.CarMapper
或解析 XML 时的错误信息。
Step 4:检查 XML 文件位置与编译输出
- 确保
CarMapper.xml放在src/main/resources/mapper/目录下(或类路径中)。 - 检查
target/classes目录下是否存在对应的 XML 文件,且路径正确。
Step 5:检查 XML 语法
- 确保所有标签都已闭合,没有多余字符。
- 如果有多个 SQL 语句,检查是否有同名的
id冲突(但这里应该不是)。
五、常见解决方案
方案一:修改 XML 中的 id
如果发现方法名和 id 不一致,统一修改即可。
方案二:修正 namespace
确保 namespace 与接口全限定名一致。
方案三:重新编译项目
有时编译缓存导致 XML 未更新,执行 mvn clean compile 重新编译。
方案四:检查是否有多个同名的 SQL 语句
如果存在多个 XML 文件定义了相同的 namespace,MyBatis 会合并,可能导致覆盖。但一般不建议这样。
方案五:使用 @Select 注解(临时替代)
如果 XML 始终无法生效,可以先用注解测试,确认接口与数据库能连通:
java
public interface CarMapper {
@Select("SELECT * FROM t_car")
List<Car> selectAllCar();
}
如果注解生效,说明是 XML 加载的问题。
六、调试技巧
1. 查看 MyBatis 启动日志
观察日志中的 ==> Preparing: 等输出,确认 SQL 是否被识别。如果没有任何日志,说明语句未被加载。
2. 调用 sqlSession.getConfiguration().getMappedStatementNames()
在测试代码中打印所有已注册的 MappedStatement 名称:
java
Collection<String> names = sqlSession.getConfiguration().getMappedStatementNames();
names.forEach(System.out::println);
如果你找不到 com.xie.mapper.CarMapper.selectAllCar,说明 XML 没有被加载。
3. 检查 XML 是否被 mappers 标签包含
确保 mybatis-config.xml 中有:
xml
<mappers>
<mapper resource="mapper/CarMapper.xml"/>
<!-- 或使用包扫描 -->
<package name="com.xie.mapper"/>
</mappers>
七、典型错误示例与修正
错误示例 1 :id 写错
xml
<select id="selectAllCar1" resultType="Car"> <!-- 多了一个 1 -->
接口是 selectAllCar,导致找不到。
错误示例 2 :namespace 写错
xml
<mapper namespace="com.xie.mapper.CarMapper2"> <!-- 与接口不符 -->
错误示例 3 :XML 文件路径错误
mybatis-config.xml 中配置:
xml
<mapper resource="CarMapper.xml"/> <!-- 但如果文件在 mapper 子目录下,应写 mapper/CarMapper.xml -->
八、最终建议
- 统一使用包扫描方式 (
<package name="com.xie.mapper"/>),它会自动加载同包下的 XML(要求 XML 与接口同名且在同一包下,或在resources中保持相同相对路径)。 - 尽量保持 XML 与接口同包同名 (在
resources中建立同样的包结构),这是最不易出错的方式。 - 如果使用
resource,建议将 XML 统一放在src/main/resources/mapper目录下,并在配置中写明相对路径。
按照上述步骤逐一排查,即可快速定位并解决 Invalid bound statement 问题。