下面这篇建议作为下一篇发,标题简单一点:

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 文档也说明,selectinsertupdatedelete 等语句里的 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/>@MapperScanMapperScannerConfigurer 自动扫描 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> {
}

这种情况下,selectByIdinsertupdateByIddeleteById 这些基础方法是 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 报错:

Spring Boot DataSource 报错怎么处理

Maven 依赖冲突:

Maven 依赖冲突怎么排查

Maven 国内镜像:

Maven 国内镜像配置教程

Spring Boot JDK 兼容:

Spring Boot JDK 兼容表

Spring Boot 2 升级 3:

Spring Boot 2 升级 3 指南

Java 开发环境配置专题:

Java开发环境配置专题


更新记录

2026-07-31:
- 创建 MyBatis Invalid bound statement 排查文章
- 增加 namespace、id、mapper-locations、@MapperScan 排查说明
- 增加 Spring Boot + MyBatis 推荐配置
- 增加多模块项目、MyBatis-Plus、自定义 XML 方法等场景
- 增加完整排查清单和常见问题