惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 聂微东
GbyAI
GbyAI
S
SegmentFault 最新的问题
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
Visual Studio Blog
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
B
Blog
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
雷峰网
雷峰网
爱范儿
爱范儿
Vercel News
Vercel News
人人都是产品经理
人人都是产品经理
U
Unit 42
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
Jina AI
Jina AI
P
Proofpoint News Feed
A
About on SuperTechFans
I
InfoQ
F
Fortinet All Blogs
L
LangChain Blog
T
Tailwind CSS Blog

沉迷在 - Java.li - 无法自拔

Spring Boot 整合 MyBatis DeepSeek Harness 深入解读 Spring Boot 连接 MySQL GitHub发生故障,崩了7个小时 Spring Boot 配置文件怎么写 SpringBoot 教程 Spring Boot 端口被占用怎么处理 Qdrant 向量数据库入门 Spring Boot 接收 JSON 参数 Spring Boot启动报错 Failed to configure a DataSource 解决办法 Maven依赖冲突怎么排查?dependency:tree、exclusions与版本统一完整教程 - 沉迷在 - Java.li - 无法自拔 给网站加一条会动的人群横幅:Little People 动画组件 Demo - 沉迷在 - Java.li - 无法自拔 【soso.re】聚合热榜 | CloudflareWorkers部分接口失效的排查与代理方案 - 沉迷在 - Java.li - 无法自拔 Spring Boot 2升级到Spring Boot 3完整指南:JDK17、javax迁移jakarta、依赖兼容与常见报错 - 沉迷在 - Java.li - 无法自拔 随机小姐姐视频 - 沉迷在 - Java.li - 无法自拔 Spring Boot与JDK版本兼容表:Spring Boot 2.x / 3.x / 4.x应该用哪个Java版本? - 沉迷在 - Java.li - 无法自拔 No compiler is provided in this environment解决办法:JDK、JRE、Maven与IDEA排查 - 沉迷在 - Java.li - 无法自拔 置身钉内|含全文 PDF - 沉迷在 - Java.li - 无法自拔 javac不是内部或外部命令怎么解决?JDK、JAVA_HOME和Path完整排查 Windows配置JAVA_HOME后不生效怎么办?java -version显示旧版本解决办法 Maven Could not transfer artifact 下载失败解决:settings.xml、国内镜像、本地缓存与代理排查 JSON转Java实体类完整教程:对象、数组、嵌套结构与LocalDateTime处理 Windows安装JDK 8 / 17 / 21 / 25完整教程:JAVA_HOME环境变量配置与验证 IDEA下载JDK很慢怎么办?手动配置本地JDK完整教程 Java版本号与class文件major version对照表:Unsupported class file major version 52 / 55 / 61 / 65 / 69 / 70 Gradle国内镜像配置教程:init.gradle、repositories与Wrapper加速完整指南 Maven国内镜像settings.xml配置大全:阿里云、腾讯云、华为云、清华源 Java开发者必备工具箱 2026年Java行情深度解读:就业真实现状、语言排名与开发者破局指南 如何防止服务器被暴力破解?2026年最全的5层防护实战指南
MyBatis Invalid bound statement 怎么处理
HiF · 2026-07-31 · via 沉迷在 - Java.li - 无法自拔

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

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 方法等场景
- 增加完整排查清单和常见问题