Spring Boot整合MyBatis-Plus案例:从零搭建高效数据访问层(附完整代码)
目录导读
- 为什么选择MyBatis-Plus? —— 对比传统MyBatis的核心优势
- 环境准备与依赖配置 —— Maven依赖、版本选择避坑指南
- 核心代码实战 —— 实体类、Mapper接口、Service层的最佳实践
- 高级特性演示 —— 条件构造器、分页插件、自动填充
- 常见问题与性能优化 —— 逻辑删除、SQL日志、连接池调优
- 问答环节 —— 解决你整合过程中的90%困惑
为什么选择MyBatis-Plus?
传统MyBatis开发中,我们常常需要为每个实体类手写CRUD的XML映射文件,繁琐且易错,MyBatis-Plus(简称MP)作为MyBatis的增强工具,在保留原生灵活性的同时,提供了开箱即用的CRUD方法、条件构造器、分页插件等特性,大幅减少样板代码,根据官方统计,使用MP后,基础数据访问代码量平均减少70%以上,而性能损耗几乎为零。

核心优势对比:
- 单表CRUD无需写SQL,直接调用
selectById()、insert()等方法 - 内置代码生成器,一键生成实体、Mapper、Service、Controller
- 提供乐观锁、逻辑删除、自动填充等企业级解决方案
- 与Spring Boot完美集成,配置极简
环境准备与依赖配置
环境要求: JDK 8+、Maven 3.6+、MySQL 5.7+(或8.0+)
关键依赖(POM.xml) 注意版本兼容性:
<!-- Spring Boot 2.7.x 为基础 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
重要配置(application.yml):
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
username: root
password: 123456
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段
logic-delete-value: 1
logic-not-delete-value: 0
mapper-locations: classpath*:/mapper/**/*.xml # 自定义XML位置
避坑提示: 如果你的Spring Boot版本是3.x,请使用
mybatis-plus-spring-boot3-starter,否则会无法启动。
核心代码实战
1 实体类(使用Lombok简化)
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic // 逻辑删除注解
private Integer deleted;
}
2 Mapper接口(继承BaseMapper)
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 自定义复杂SQL方法,例如多表联查
List<UserVO> selectUserWithOrders(@Param("userId") Long userId);
}
注意: 无需写任何CRUD方法,MyBatis-Plus已经内置了insert、selectById、updateById等20+常用方法。
3 Service层(继承IService)
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
// 直接使用 this.save()、this.list() 等
public List<User> getAdultUsers() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(User::getAge, 18);
return this.list(wrapper);
}
}
高级特性演示
1 条件构造器(Wrapper)
这是MP最强大的功能之一,可以避免编写大量动态SQL。
// 链式查询:年龄在20-30之间且名字包含"张"的用户
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.between(User::getAge, 20, 30)
.like(User::getName, "张")
.orderByDesc(User::getUpdateTime);
List<User> users = userMapper.selectList(wrapper);
2 分页插件配置
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
// 使用分页
Page<User> page = new Page<>(1, 10); // 第1页,每页10条
Page<User> result = userMapper.selectPage(page, null);
System.out.println("总记录数:" + result.getTotal());
3 自动填充(审计字段)
通过MetaObjectHandler实现创建/更新时间自动填入。
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
常见问题与性能优化
| 问题场景 | 解决方案 |
|---|---|
| 表名与实体类名不一致 | 使用@TableName("实际表名") |
| 主键自增失效 | 确保数据库主键AUTO_INCREMENT,实体ID用IdType.AUTO |
| 查询性能慢 | 开启SQL日志,检查是否走了索引;可配合@SqlParser过滤 |
| 逻辑删除导致唯一索引冲突 | 将逻辑删除字段与一个唯一键组合,或使用UUID |
性能优化建议:
- 统一使用
LambdaQueryWrapper避免字符串硬编码 - 大批量插入时使用
saveBatch(),默认批处理大小1000 - 在
application.yml中配置mybatis-plus.configuration.map-underscore-to-camel-case: true(默认开启)
问答环节
Q1:MyBatis-Plus是否取代了MyBatis? 不是取代,而是增强,MP内部依然依赖MyBatis的SqlSessionFactory,你完全可以混合使用:简单CRUD用MP,复杂SQL用原生XML。
Q2:如何避免实体属性与数据库字段映射失败?
如果你使用的是user_name这种下划线风格,MP默认会自动映射为userName,如果映射始终报错,检查是否关闭了map-underscore-to-camel-case配置。
Q3:多租户或数据权限隔离怎么办?
MP提供了TenantLineInnerInterceptor插件,可以自动在SQL后追加WHERE tenant_id = ?,具体实现请参考官方文档的“多租户插件”章节。
Q4:整合后启动报错Invalid bound statement (not found)
通常是因为@Mapper注解所在的类没有被Spring扫描,解决方法:在启动类添加@MapperScan("com.example.mapper"),或在每个Mapper上标注@Mapper(已添加)。
Q5:使用MP后,事务管理是否受影响?
完全不受影响,你依然可以在Service方法上使用@Transactional,MP的CRUD操作会自动参与事务。
通过本文的案例实践,你应该已经掌握Spring Boot整合MyBatis-Plus的核心思路,从基础配置到条件构造器、分页、自动填充,每一步都伴随着真实可运行的代码,MyBatis-Plus带来的开发效率提升是立竿见影的,但切记:当业务走向复杂时,灵活结合原生SQL依然是关键技能,建议后续深入阅读其官方文档中的“插件扩展”和“SQL注入器”章节,以应对更多业务场景。