当前位置: 首页 > news >正文

MyBatis-Plus 进阶实战|告别只会CRUD!搞定企业级高频场景

很多小伙伴开发时都会遇到一堆问题:

复杂多条件模糊查询怎么写?并发更新数据错乱怎么办?逻辑删除后统计数据不准?批量新增效率低?自定义SQL怎么和MP混用?

只会基础CRUD,只能应付简单demo。真正的企业项目,全靠MP高阶功能撑场面。

今天这篇进阶干货,专门解决工作中90%的MP实战难题,看完直接适配生产环境开发!


一、先划重点:MP进阶核心思维

很多人用MP有个误区:把MP当成“只会生成SQL的工具”。

实际上企业级MP核心用法就两点:

1)简单业务:全程用MP条件构造器,零SQL开发

2)复杂业务/多表联查:MP与原生SQL混用,灵活不冲突

下面全是生产级高频用法,直接复制就能用!

二、LambdaQueryWrapper 高阶查询(避坑版)

基础的等值、范围查询大家都会,工作中最常用、最容易出错的是动态多条件拼接。

场景:后台列表查询,用户名、年龄、邮箱都是非必传参数,传了才查询,不传不生效。

1)新手错误写法

无脑拼接条件,容易出现空字符串、null导致查询数据异常:

// 极易出Bug!空参数也会拼接条件

wrapper.like(User::getUsername, username);

wrapper.gt(User::getAge, age);

2)进阶优雅写法(带条件判断)

MP自带 condition 参数,满足条件才拼接SQL,超级简洁:

public List<User> getUserList(String username, Integer age, String email){

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

// 仅当用户名不为空时,执行模糊查询

wrapper.like(StringUtils.hasText(username), User::getUsername, username)

// 仅当年龄不为null时,执行大于查询

.gt(age != null, User::getAge, age)

// 仅当邮箱不为空时,精准匹配

.eq(StringUtils.hasText(email), User::getEmail, email);

return userMapper.selectList(wrapper);

}

核心技巧:所有条件构造方法的第一个参数,都可以加布尔判断,彻底干掉一堆 if-else,代码干净又安全!

拓展:排序、去重、指定字段查询

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

// 只查询指定字段,避免查询全部字段浪费性能

wrapper.select(User::getId, User::getUsername, User::getAge);

// 年龄倒序,创建时间正序

wrapper.orderByDesc(User::getAge)

.orderByAsc(User::getCreateTime);

// 去重查询

wrapper.distinct(true);

三、批量操作:告别for循环单条保存

新手开发批量新增/修改,总喜欢用 for循环 + insert/update,数据库频繁交互,性能极差。

MP内置ServiceImpl,自带高效批量方法,底层是批量预处理SQL,性能碾压循环操作。

1. 先改造Service层(进阶必备)

基础Mapper只适合单条操作,批量操作必须用IService:

// Service接口

public interface UserService extends IService<User> {}

// Service实现类

@Service

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}

2. 高效批量新增/修改

@Autowired

private UserService userService;

// 批量新增

@Test

void batchSave(){

List<User> userList = new ArrayList<>();

// 批量封装数据...

userService.saveBatch(userList);

}

// 批量更新(根据ID)

@Test

void batchUpdate(){

List<User> userList = new ArrayList<>();

userService.updateBatchById(userList);

}

小细节:批量方法支持设置批次大小,saveBatch(list, 1000),适配大数据量场景,避免一次性数据过多报错。

四、乐观锁:解决并发更新数据丢失问题

生产高频Bug:多人同时修改同一条数据,后提交的数据会覆盖先提交的数据,导致数据丢失。

MP自带乐观锁插件,无需手写锁逻辑,完美解决并发更新问题。

1. 数据库加版本字段

新增字段:version int default 1 comment '版本号'

2. 实体类添加注解

@Version // 乐观锁版本号注解

private Integer version;

3. 开启乐观锁插件

@Bean

public MybatisPlusInterceptor mybatisPlusInterceptor(){

MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

// 添加乐观锁插件

interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

return interceptor;

}

实现原理:每次更新会校验版本号,更新成功版本号+1;如果版本号不匹配(被他人修改过),更新失败,避免数据覆盖。

五、MP + 自定义SQL 完美混用

MP不是万能的,多表联查、复杂统计、子查询,还是原生SQL最顺手。

重点:MP可以和原生MyBatis完全混用,互不冲突!

1. Mapper自定义方法

// 自定义多表查询方法

List<UserVO> getUserAndDeptList();

2. 对应XML写原生SQL

正常写联查、统计SQL即可,MP的分页、日志、插件依旧生效,完全兼容。

六、生产避坑:逻辑删除的隐形坑

上篇讲过逻辑删除,但很多人上线后出问题:统计表数据不准、自定义SQL查不到已删除数据。

坑点:

开启逻辑删除全局配置后,MP会自动在所有查询拼接 where deleted=0。

解决方案:

需要查询全部数据(包含已删除)时,手动关闭当前查询的逻辑删除:

// 忽略逻辑删除,查询所有数据

QueryWrapper<User> wrapper = new QueryWrapper<>().setSqlSelect("*");

wrapper.last("limit 100");

// 核心:关闭本次查询逻辑删除

userMapper.selectList(wrapper.ignoreLogicDelete());

七、高级查询:分页+条件+排序 组合实战

给大家一套项目通用的后台列表分页模板,直接复用:

public Page<User> pageUser(Integer pageNum, Integer pageSize, String username, Integer age) {

// 分页参数

Page<User> page = new Page<>(pageNum, pageSize);

// 动态条件

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

wrapper.like(StringUtils.hasText(username), User::getUsername, username)

.gt(age != null, User::getAge, age)

.orderByDesc(User::getCreateTime);

// 分页查询

return userMapper.selectPage(page, wrapper);

}

http://www.rkmt.cn/news/1418155.html

相关文章:

  • Cursor AI Pro破解工具:智能解锁神器,告别试用限制的终极解决方案
  • 基于Arduino与3D打印的BB-8球形机器人制作全攻略
  • 徐州地铁旁高端写字楼
  • 告别卡顿!在AMD笔记本(如R7 6800H)上用VMware流畅运行macOS开发环境的完整配置流程
  • 食品包装AI质检时代来了,标签审核效率提升千倍
  • 订单超时库存不释放?手把手教你用RabbitMQ死信队列实现自动解锁(SpringBoot实战)
  • 保姆级教程:在Ubuntu Server 22.04上搞定图形桌面和VNC远程连接(含RealVNC账号注册避坑)
  • 别再被Finder骗了!Mac里多出来的那个‘Macintosh HD’到底是什么?APFS卷组与firmlink机制全解析
  • 3D打印热床附着力与高温PI胶带应用技术指南
  • 用Python玩转强化学习:从‘赌徒问题’实战理解MDP的策略迭代与价值迭代
  • 避坑指南:macOS重装/降级时,磁盘工具抹掉选项怎么选?APFS还是Mac OS扩展?
  • 一文读懂AI人工智能:从概念到范式,小白也能秒懂
  • pdfClaw免登录在线PDF转Word
  • 丰城高端全屋定制商家如何选择?
  • 基于Arduino与MAX7219的复古LED点阵时钟DIY:从硬件选型到外壳制作
  • 鼎讯信通 RM‑1000 高性能无线电综合测试仪:铁路通信电台检测优选
  • 家常饮用养生酒,六味地黄酒暖心相伴
  • AI发现潜伏18年的NGINX高危漏洞:CVE-2026-42945完整技术分析
  • 免费.brd文件查看器终极指南:OpenBoardView让电路板设计查看如此简单
  • 视频中如何添加自定义水印,一招搞定
  • 3个真实场景告诉你:为什么猫抓插件是网页视频下载的终极解决方案?
  • 别再只用准确率了!用Python实战Cohen‘s Kappa评估你的分类模型(附代码避坑指南)
  • 2026年当前,谁在定义靠谱优秀的钢制活动柜生产厂商新标准? - 2026年企业资讯
  • 别再死记硬背!彻底搞懂 Java 泛型通配符、协变逆变与 PECS 原理
  • 注塑车间的透明化革命:盘古信息如何重塑注塑成型行业的数字未来?
  • 2026年5月衡水档案柜之选:深度剖析河北精纳金属制品有限公司 - 2026年企业资讯
  • 知识IP卡在变现第一步:创客匠人用一套陪跑系统回答“谁来陪你落地”
  • 限时解密|金融/医疗/教育三大垂直领域AI语音合成真实落地瓶颈:92%项目因“微表情语音失真”遭客户拒用
  • 制作儿童英文教学视频的AI工具选型指南
  • 最全整理|Claude Code 180+ 运行状态词