
本系列参考黑马程序员微服务课程,有兴趣的可以去查看相关视频,本系列内容采用渐进式方式讲解微服务核心概念与实践方法,每日更新确保知识点的连贯性。通过系统化学习路径帮助开发者掌握分布式系统构建的关键技术。读者可通过平台订阅功能获取最新章节推送,及时了解服务拆分、容器化部署、服务网格等前沿技术动态。
- 个人主页:VON
- 文章所属专栏:微服务
- 系列文章链接:重生之我在暑假学习微服务第一天《MybatisPlus-上篇》-CSDN博客
- 时间:每天12点准时更新
特别声明:本篇文章对应黑马程序员微服务课程P11-P20
目录
[MyBatis-Plus 插件的意义](#MyBatis-Plus 插件的意义)
[3. 配置所需信息](#3. 配置所需信息)
[4. 配置成自己的](#4. 配置成自己的)
[MyBatis-Plus 中的处理器](#MyBatis-Plus 中的处理器)
分页插件处理器(PaginationInnerInterceptor)
动态表名处理器(DynamicTableNameInnerInterceptor)
乐观锁处理器(OptimisticLockerInnerInterceptor)
[SQL 注入处理器(AbstractSqlInjector)](#SQL 注入处理器(AbstractSqlInjector))
性能分析处理器(PerformanceInterceptor)
[编辑 2、用户继承该实体类](#编辑 2、用户继承该实体类)
前言
窗外的蝉鸣又起时,VON 的笔记本已经写满半本。晨光漫过屏幕,照亮他眼下淡淡的青黑 ------ 凌晨三点才在代码调试成功的提示音里睡去,七点却被生物钟拽醒。
他点开《MyBatisPlus 基础入门》的第三章,指尖在手机屏幕上飞快滑动。@TableName 注解那页还粘着昨晚吃泡面时溅的汤渍,此刻倒成了醒目的标记。"原来实体类和数据库表名不一致时,加这个注解就能映射..." 他对着示例敲下代码,看着控制台弹出的 "查询成功" 提示,突然想起前世写的那堆冗长 SQL,耳根发烫。
条件构造器是块硬骨头。QueryWrapper 的嵌套查询让他卡了整整两小时,报错信息像密集的蚂蚁爬满屏幕。窗外的蝉鸣又开始聒噪,他抓着头发盯着那句 "LambdaQueryWrapper lqw = new LambdaQueryWrapper<>()",忽然想起班长发的资料里提过" 链式调用更直观 "。指尖在键盘上重新跳跃,当根据年龄和性别筛选出的用户列表整齐排列在控制台时,他狠狠捶了下桌面,震得马克杯里的速溶咖啡泛起涟漪。
自定义 SQL 部分倒意外顺利。或许是前世被冗余代码折磨出的本能,当他在 XML 文件里写出带条件判断的动态 SQL 时,竟有种莫名的熟悉感。阳光穿过纱窗在代码上投下格子影,他忽然发现,那些曾经让他望而生畏的尖括号,此刻正像列队的士兵般温顺。
下午三点,Service 接口的批量新增测试成功。看着一百条用户数据瞬间写入数据库,VON 摸出手机翻到游戏群,前世此刻他本该在喊 "开团"。群里依旧热闹,他却平静地点了退出。
最后一行代码运行结束时,晚霞正把天空染成橘红色。VON 合上笔记本,发现封面上的倒影里,自己的眼睛比昨天更亮了些。蝉鸣渐歇的暮色里,他仿佛听见未来的自己敲代码的声音,清脆又笃定。
至此,MybatisPlus篇完结!!!
一、安装插件
MyBatis-Plus 插件的意义
MyBatis-Plus(简称 MP)是基于 MyBatis 的增强工具插件,旨在简化开发、提升效率。其核心意义在于为 MyBatis 提供更便捷的功能扩展,同时保持与原生 MyBatis 的无缝兼容。
1.找到idea中的插件

2.在插件市场中搜索MyBatisPlus插件

3. 配置所需信息

4. 配置成自己的

这里测试的时候报错了,问了下豆包,说是时区问题。
The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
修改方案:

这样就表示成功了

5.接下来就可以直接使用了

可以看到这里出现的表正是我们数据库中的表

6.开始生成
配置成我这样就可以

出现这个标志就成功了
这些全都是这个插件生成的代码

二、DB静态工具
DB静态工具是指用于数据库设计、分析、优化的非运行时工具,通常在数据库开发或维护阶段使用。这类工具不直接与运行中的数据库交互,而是通过静态分析数据结构、SQL脚本或元数据来提供支持。
测试一:改造根据id查询
1.先导入AddressVO

2.在UserVO中添加AddressVO字段
3.开始修改代码
原UserController

现UserController

实现方法

4.用Apifox测试
测试成功

测试二:改造根据id批量查询
1.还是先改造Controll层代码

2.实现方法
java
@Override
public List<UserVO> queryUsersAndAddressByIds(List<Long> ids) {
//1.查询用户
List<User> users = listByIds(ids);
if(CollUtil.isEmpty(users)){
return Collections.emptyList();
}
//2.查询地址
//获取id集合
List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
List<Address> address = Db.lambdaQuery(Address.class)
.in(Address::getUserId, userIds)
.list();
List<AddressVO> addressVOList = BeanUtil.copyToList(address, AddressVO.class);
Map<Long, List<AddressVO>> addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
//3.封装VO
List<UserVO> userVOList = BeanUtil.copyToList(users, UserVO.class);
userVOList.forEach(userVO -> {
userVO.setAddress(addressMap.get(userVO.getId()));
});
return userVOList;
}
3.解释方法
这个方法有点复杂了,这里解释一下相关步骤
(1)查询用户基本信息
java
List<User> users = listByIds(ids);
if(CollUtil.isEmpty(users)){
return Collections.emptyList();
}
- 使用 listByIds(ids) 方法根据ID列表批量查询用户
- 如果查询结果为空,则返回空列表
(2)查询用户地址信息
java
List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
List<Address> address = Db.lambdaQuery(Address.class)
.in(Address::getUserId, userIds)
.list();
- 从查询到的用户列表中提取所有用户ID
- 使用 Db.lambdaQuery() 构造查询条件,通过 in 条件批量查询这些用户的所有地址信息
(3)地址信息处理和分组
java
List<AddressVO> addressVOList = BeanUtil.copyToList(address, AddressVO.class);
Map<Long, List<AddressVO>> addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
- 使用 BeanUtil.copyToList() 将 Address 对象列表转换为 AddressVO 对象列表
- 使用 Collectors.groupingBy() 按用户ID对地址进行分组,形成 Map<用户ID, 地址列表> 的结构
(4)封装最终结果
java
List<UserVO> userVOList = BeanUtil.copyToList(users, UserVO.class);
userVOList.forEach(userVO -> {
userVO.setAddress(addressMap.get(userVO.getId()));
});
return userVOList;
- 将用户信息转换为 UserVO 对象列表
- 遍历每个 UserVO 对象,从 addressMap 中获取对应用户ID的地址列表并设置到 UserVO 中
- 返回封装好的用户VO列表
4、测试结果
可以看到可以正常查询

三、逻辑删除
逻辑删除是一种数据管理方式,通过标记记录的状态而非物理删除数据。通常通过添加一个字段(如 is_deleted
、status
)标识记录是否"已删除",实际数据仍保留在数据库中。
1.先配置逻辑删除相关语句

2.新建一个测试

3.测试结果

4.查看数据库表结构
不难看出这里的deleted字段变成了true,说明已经被逻辑删除掉了
四、处理器
MyBatis-Plus 中的处理器
MyBatis-Plus 提供了多种处理器(Handler)用于扩展或定制框架行为,主要分为以下几类:
元对象处理器(MetaObjectHandler)
用于自动填充公共字段(如创建时间、更新时间、操作人等)。通过实现 MetaObjectHandler
接口并重写以下方法:
java
@Override
public void insertFill(MetaObject metaObject) {
// 插入时自动填充字段
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
// 更新时自动填充字段
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
需通过 @Component
注解注册为 Spring Bean。
分页插件处理器(PaginationInnerInterceptor)
用于实现物理分页功能,需通过配置类启用:
java
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
支持多种数据库方言,自动识别并转换分页语句。
动态表名处理器(DynamicTableNameInnerInterceptor)
用于动态替换表名,适用于分表场景:
java
DynamicTableNameInnerInterceptor interceptor = new DynamicTableNameInnerInterceptor();
interceptor.setTableNameHandler((sql, tableName) -> {
return "实际表名逻辑";
});
乐观锁处理器(OptimisticLockerInnerInterceptor)
通过版本号实现乐观锁,需在实体类字段添加 @Version
注解:
java
@Version
private Integer version;
配置拦截器后,更新操作会自动检测版本号一致性。
SQL 注入处理器(AbstractSqlInjector)
用于自定义全局 SQL 方法,需继承 AbstractSqlInjector
并实现 inspectInject
方法:
java
public class CustomSqlInjector extends AbstractSqlInjector {
@Override
public List<AbstractMethod> getMethodList() {
return Stream.of(new InsertBatchSomeColumn()).collect(Collectors.toList());
}
}
性能分析处理器(PerformanceInterceptor)
已废弃,推荐使用第三方监控工具(如 P6Spy)替代。
注意事项
- 处理器需通过
MybatisPlusInterceptor
的addInnerInterceptor
方法添加 - 多个拦截器按添加顺序执行
- 部分处理器需配合注解或实体类字段使用
可以看到处理器的类型十分丰富,这里给大家详解一下以下两个处理器的使用
1、枚举处理器
(1)新建一个枚举文件来存放枚举类型

(2)配置枚举处理器
(3)修改实体类

(4)修改代码
将出现的状态码都修改一下

UserVO实体类也要改一下
(5)测试
测试一下观察返回值
这里返回值变成了枚举类型的,这可不是我们想要的结果

解决方案也很简单,只需要添加这么一个注解即可

可以看到这是展现的就是我们预期的效果了

2、JSON处理器
JSON 处理器是一种用于解析、生成、转换和操作 JSON(JavaScript Object Notation)数据的工具或库。其核心功能包括:
- 解析:将 JSON 字符串转换为编程语言中的数据结构(如对象、字典、数组等)。
- 序列化:将内存中的数据结构转换为 JSON 字符串。
- 查询与修改:支持路径查询(如 JSONPath)、节点增删改查等操作。
- 验证:检查 JSON 数据是否符合特定模式(如 JSON Schema)。
- 格式化:美化或压缩 JSON 字符串以提高可读性或传输效率。
先创建实体类

注:要和表中数据保持一致

这里的字段也要加一下注解

添加这一字段

这里也要修改一下,凡是涉及到的都要修改

就像这样的,都要修改为上面那种

UserVO实体类也要改
改为UserInfo

测试
不难看出这里的info字段变成了json格式

五、分页插件
分页插件是一种用于将大量数据分割成多个页面的工具,通常用于网页或应用程序中,以提高数据加载效率和用户体验。它允许用户通过导航按钮(如上一页、下一页、页码跳转)浏览不同页面的数据,避免一次性加载全部内容。
1、先配置实体类

2、测试
注意一下这里的page包,别导入错了

这里当时添加数据后忘记删除了

可以看到我们设置的每页2条数据,5条数据正好三页。

六、分页查询案例

1、先创建实体类
2、用户继承该实体类

3、定义返回结果

4、开始测试

service层代码
java
@Override
public PageDTO<UserVO> queryUsersPage(UserQuery query) {
String name = query.getName();
Integer status = query.getStatus();
Page<User> page = new Page<>(query.getPageNo(), query.getPageSize());
if(StrUtil.isNotBlank(query.getSortBy())){
//不为空
page.addOrder(new OrderItem(query.getSortBy(), query.getIsAsc()));
}else{
page.addOrder(new OrderItem("update_time", false));
}
Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page( page);
//封装
PageDTO<UserVO> dto = new PageDTO<>();
dto.setTotal(p.getTotal());
dto.setPages(p.getPages());
List<User> records = p.getRecords();
if(records != null){
List<UserVO> vos = BeanUtil.copyToList(records, UserVO.class);
dto.setList(vos);
}
return dto;
}
测试结果

mybatisplus篇结尾
MyBatis-Plus作为一款强大的MyBatis增强工具,极大简化了开发者的数据库操作流程,提升了开发效率。通过自动生成代码、内置通用Mapper和Service,开发者可以专注于业务逻辑的实现,减少重复性工作。
MyBatis-Plus支持多种数据库,并提供丰富的查询条件构造器,满足复杂查询需求。其强大的性能优化和灵活的插件机制,使得数据库操作更加高效和安全。无论是新项目搭建还是旧项目改造,MyBatis-Plus都能提供便捷的解决方案。
在实际开发中,合理使用MyBatis-Plus的功能,可以显著提升开发效率和代码质量。结合Spring Boot等框架,能够快速构建稳定可靠的企业级应用。持续关注MyBatis-Plus的更新和社区动态,能够更好地利用其最新特性。
总结与展望
MyBatis-Plus的未来发展潜力巨大,随着技术的不断进步,更多实用功能将被引入。开发者应持续学习和实践,充分利用MyBatis-Plus的优势,构建高效、可维护的应用程序。