这是一个非常关键且常见的问题。答案是:
如果每个 Mapper 接口上都显式添加了
@Mapper注解,那么通常不再需要@MapperScan。
但是否“完全不需要”,还需结合项目实际情况来判断。下面详细说明:
✅ 一、两种方式的作用
| 方式 | 说明 |
|---|---|
@Mapper(接口上) | 标记单个接口为 MyBatis Mapper,Spring 会将其注册为 Bean |
@MapperScan(启动类上) | 批量扫描指定包下的所有接口,自动注册为 Mapper Bean,无需每个接口加 @Mapper |
✅ 二、使用 @Mapper 后是否还需要 @MapperScan?
✅ 情况 1:所有 Mapper 接口都加了 @Mapper
- 不需要
@MapperScan - Spring 在组件扫描时会自动识别带
@Mapper的接口并注册 - ✅ 推荐做法:清晰、显式、便于 IDE 理解(如跳转、重构)
⚠️ 情况 2:部分接口加了 @Mapper,部分没加
- 没加
@Mapper的接口不会被注册 → 启动报错(Invalid bound statement) - 此时若想统一管理,建议统一使用
@MapperScan并移除所有@Mapper
❌ 情况 3:既加了 @Mapper,又配置了 @MapperScan
- 不会冲突,MyBatis-Spring 会去重处理
- 但属于冗余配置,不推荐(增加理解成本)
✅ 三、最佳实践建议(企业级项目)
| 场景 | 推荐方案 |
|---|---|
| 小型项目 / 快速开发 | 使用 @MapperScan(简洁,少写注解) |
| 中大型项目 / 团队协作 / 代码可读性优先 | 每个 Mapper 接口显式加 @Mapper,不使用 @MapperScan |
| 混合遗留项目 | 统一风格,避免混用 |
📌 主流趋势:越来越多团队倾向于 显式标注
@Mapper,理由如下:
- 代码自解释性强(看到接口就知道是 Mapper)
- IDE 支持更好(如 Spring 插件能识别 Bean)
- 避免因
@MapperScan包路径错误导致“部分 Mapper 未加载”的隐蔽问题- 符合“显式优于隐式”(Explicit is better than implicit)的工程哲学
✅ 四、示例对比
方案 A:使用 @Mapper(推荐)
// UserMapper.java
@Mapper
public interface UserMapper extends BaseMapper<User> { }
// 启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// ✅ 无需 @MapperScan
方案 B:使用 @MapperScan
// UserMapper.java(无注解)
public interface UserMapper extends BaseMapper<User> { }
// 启动类
@SpringBootApplication
@MapperScan("com.example.demo.mapper") // 扫描包
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
✅ 五、常见误区澄清
| 误区 | 正确理解 |
|---|---|
“必须用 @MapperScan 才能用 MyBatis” | ❌ 错!@Mapper 单独即可 |
“用了 @Mapper 还要配 @MapperScan 才保险” | ❌ 冗余,无必要 |
“XML 文件必须配合 @MapperScan” | ❌ XML 与注解方式无关,只与 Mapper 接口是否被注册有关 |
✅ 总结
如果你在
mapper.java.ftl模板中已经为每个 Mapper 接口添加了@Mapper注解,那么你的 Spring Boot 启动类中就不再需要@MapperScan。
这是标准、安全、可维护的做法,尤其适合通过代码生成器批量生成 Mapper 的场景。
✅ 最终建议:
- 模板中保留
@Mapper - 启动类不要加
@MapperScan - 保持风格统一,避免混用
7141

被折叠的 条评论
为什么被折叠?



