在 Spring Boot 项目中使用 MyBatis 作为持久层框架时,最关键的一步就是让 Spring 容器正确识别并注册 Mapper 接口。如果扫描路径配置不对,启动项目时往往会出现 NoSuchBeanDefinitionException 或者 Invalid bound statement 这类让人头疼的报错。本文将完整演示从依赖引入到扫描配置的全过程,并对比几种主流配置方案的优劣。

一、引入依赖与基础配置
首先在 pom.xml 中添加相关依赖。传统的做法是引入 mybatis-spring-boot-starter 和数据库驱动,新版 Spring Boot 3.x 建议使用 mybatis-spring-boot-starter 3.x 版本以兼容 jakarta 命名空间。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>接着在 application.yml 中配置数据源与 MyBatis 参数。注意 mapper-locations 指向的是 XML 映射文件的位置,默认值是 classpath*:/mapper/**/*.xml,如果你的 XML 放在 src\main\resources\mapper 目录下,保持默认即可。
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.example.demo.entity
configuration:
map-underscore-to-camel-case: truemap-underscore-to-camel-case 开启后,数据库中的 user_name 字段会自动映射到 Java 实体的 userName 属性,省去了大量手动 resultMap 配置。type-aliases-package 则允许在 XML 中直接写类名而不用写全限定名。
二、两种 Mapper 扫描方式对比
方式一是给每个 Mapper 接口添加 @Mapper 注解,MyBatis 的自动配置类会扫描带有该注解的接口并注册为 Bean。这种方式适合项目较小、Mapper 数量不多的场景,优点是明确直观,缺点是每个接口都要加注解,容易遗漏。
@Mapper
public interface UserMapper {
User selectById(Long id);
List<User> selectAll();
}方式二是在启动类或任意一个配置类上添加 @MapperScan 注解,指定包路径后,该包及其子包下的所有接口都会被扫描注册。这是企业项目中最常用的方式,推荐将所有 Mapper 接口统一放在 com.example.demo.mapper 包下,做到结构清晰。
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}两种方式不要混用。如果同时使用,@MapperScan 的优先级更高,但混用会增加维护成本。另外要注意 @MapperScan 扫描的是包下所有接口,如果该包中存在非 Mapper 的接口,会被误注册,因此务必保持包职责单一。
三、多包扫描与进阶配置
当项目拆分成多个模块,Mapper 分散在不同包中时,@MapperScan 支持数组形式配置多个路径,也可以使用通配符。
@SpringBootApplication
@MapperScan({"com.example.demo.mapper", "com.example.order.mapper"})
public class DemoApplication {
}如果希望通过配置文件灵活控制扫描路径,可以借助 @Value 注入属性值,或者使用 MapperScannerConfigurer 以编程方式配置,适合需要根据环境动态调整的多模块架构。
@Configuration
public class MyBatisConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.example.*.mapper");
configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
return configurer;
}
}四、常见扫描失效问题排查
第一类问题是启动报 NoSuchBeanDefinitionException,通常是 @MapperScan 的包路径写错,或者启动类不在 Mapper 包的父级目录导致默认扫描没覆盖到。检查包名拼写是否与实际目录一致,例如接口在 com\example\demo\mapper 下,扫描路径就必须完全匹配。
第二类问题是 Invalid bound statement (not found),这其实不是扫描问题,而是接口方法找不到对应的 SQL。原因是 mybatis 的 mapper-locations 没有覆盖到 XML 文件的实际位置,或者 XML 中的 namespace 与接口全限定名不一致,也可能是方法名与 SQL 的 id 对不上。逐一核对这个三要素即可解决。
第三类是多模块项目中 XML 文件被过滤掉。如果 XML 放在 src\main\java 目录下,Maven 默认不会打包 java 目录中的非 class 文件,需要在 pom.xml 中显式声明资源过滤,或者干脆把 XML 统一放到 src\main\resources\mapper 目录下,这也是最省心的做法。
总结一下,Spring Boot 整合 MyBatis 的核心就是依赖、数据源配置和 Mapper 扫描三件事。小项目用 @Mapper 注解足够,中大型项目推荐 @MapperScan 统一管理扫描路径,同时规范 Mapper 接口包和 XML 文件目录的结构,可以避免绝大多数整合问题。
Spring BootMyBatisMapper扫描修改时间:2026-09-02 02:46:25