发布时间:2026/8/21 21:58:15
03-MyBatis-Plus全功能实战:CRUD、条件构造器、分页、排序 MyBatis-Plus全功能实战CRUD、条件构造器、分页、排序黒漂技术佬 · 2026年7月前言前一篇文章我们啃完了 MyBatis 的原生招式Mapper XML、动态 SQL、#{}防注入、ResultMap 嵌套映射。学完这些你写个无人售货柜商品管理的后台已经不在话下。但是——你是不是也感觉到了单表 CRUD 这种事翻来覆去就是那几句 SQLSELECT*FROMt_deviceWHEREid?INSERTINTOt_device...UPDATEt_deviceSET...DELETEFROMt_deviceWHEREid?每张表都写一遍你烦不烦反正我烦了。于是就有了这篇文章的主角MyBatis-Plus简称 MP。MP 不是替代 MyBatis而是在 MyBatis 之上做增强。你之前学的 Mapper XML、动态 SQL 原封不动还能用MP 只是在此基础上帮你把重复劳动省掉。听起来是不是很诱人开搞。一、什么是 MyBatis-PlusMyBatis-Plus 是 MyBatis 的增强工具包内置通用 Mapper、通用 Service提供分页插件、条件构造器、代码生成器等能力目标是只做增强不做改变。简单翻译一下你原来怎么写 MyBatis 还怎么写但 MP 帮你吃掉了一大堆 boilerplate样板代码。举个例子不用 MP 的时候每种单表查询你都要在 XML 里写select有了 MP 之后MapperpublicinterfaceDeviceMapperextendsBaseMapperDevice{// 什么都不用写CRUD 自动有了}继承了BaseMapperT你直接就能调用deviceMapper.selectById(1L);// 查一条deviceMapper.selectList(null);// 查全部deviceMapper.insert(device);// 插入deviceMapper.updateById(device);// 更新deviceMapper.deleteById(1L);// 删除单表操作从此再也不写 XML爽不爽二、快速开始pom.xml 引入dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.5/version/dependencyapplication.ymlmybatis-plus:mapper-locations:classpath*:/mapper/**/*.xml# XML 路径如果需要configuration:map-underscore-to-camel-case:true# 驼峰转换log-impl:org.apache.ibatis.logging.stdout.StdOutImpl# SQL 日志global-config:db-config:id-type:auto# 主键自增策略logic-delete-field:is_deleted# 逻辑删除字段logic-delete-value:1logic-not-delete-value:0配置项和原生 MyBatis 高度兼容只是换了个前缀mybatis-plus。三、实体类注解告诉 MP 你的表长什么样DataTableName(t_device)// 指定表名publicclassDevice{TableId(typeIdType.AUTO)// 主键自增privateLongid;TableField(device_sn)// 字段名和属性名不一致时指定privateStringdeviceSn;// 货柜设备编号TableField(device_name)privateStringdeviceName;// 设备名称如 A栋1F饮料柜privateStringlocation;// 安装位置TableField(valuestatus,existtrue)privateIntegerstatus;// 1在线 0离线TableField(fillFieldFill.INSERT)privateLocalDateTimecreateTime;TableField(fillFieldFill.INSERT_UPDATE)privateLocalDateTimeupdateTime;TableLogicprivateIntegerisDeleted;// 逻辑删除标记TableField(existfalse)// 数据库里没有这个字段privateStringstatusText;// 前端展示用在线/离线}逐一说明注解作用典型场景TableName指定实体对应的表名表名和类名不一致时必须加TableId标注主键字段指定生成策略IdType.AUTO自增IdType.ASSIGN_ID雪花算法TableField指定属性对应的列名数据库叫device_snJava 叫deviceSn时用TableField(exist false)标记非数据库字段临时计算结果、前端拼接文本等TableLogic逻辑删除标记delete 操作自动转为 updateTableField(fill ...)配合自动填充使用创建时间、更新时间自动注入TableId(type IdType.ASSIGN_ID)用的是雪花算法Snowflake生成的是一个 64 位的 Long 型 ID全局唯一。在分布式场景比如多台无人售货柜各自生成订单号下非常有用避免 ID 冲突。四、条件构造器没有 XML 的复杂查询这是 MyBatis-Plus 最核心也最强大的功能。如果只靠BaseMapper的默认方法只能做selectById、selectList这种简单操作。真正的业务查询——“查询所有在线的设备”、“按设备名称模糊搜索”、“按安装时间范围筛选”——需要条件构造器。MP 提供了两种条件构造器构造器特点推荐场景QueryWrapper字符串写列名拼错不报错简单查询、快速原型LambdaQueryWrapperLambda 表达式写列名编译期检查正式项目一律用这个4.1 LambdaQueryWrapper 常用 APIAutowiredprivateDeviceMapperdeviceMapper;// 1. 等值查询查询所有在线设备ListDeviceonlineDevicesdeviceMapper.selectList(newLambdaQueryWrapperDevice().eq(Device::getStatus,1));// 2. 模糊查询按设备名称搜索ListDevicedevicesdeviceMapper.selectList(newLambdaQueryWrapperDevice().like(Device::getDeviceName,饮料柜));// 3. 范围查询查找某个时间段内安装的设备ListDevicerecentDevicesdeviceMapper.selectList(newLambdaQueryWrapperDevice().between(Device::getCreateTime,LocalDateTime.of(2026,1,1,0,0),LocalDateTime.now()));// 4. IN 查询查多个指定设备ListDeviceselecteddeviceMapper.selectList(newLambdaQueryWrapperDevice().in(Device::getId,1L,3L,5L,7L));// 5. 组合条件在线 位置在北京 按创建时间倒序ListDeviceresultdeviceMapper.selectList(newLambdaQueryWrapperDevice().eq(Device::getStatus,1).likeRight(Device::getLocation,北京).orderByDesc(Device::getCreateTime).last(LIMIT 10)// 拼原生 SQL 片段);4.2 常用条件方法速查表方法含义SQL 等价eq等于column valuene不等于column valuegt / ge大于 / 大于等于column value/column valuelt / le小于 / 小于等于column value/column valuelike全模糊匹配column LIKE %value%likeLeft左模糊column LIKE %valuelikeRight右模糊column LIKE value%between范围column BETWEEN v1 AND v2in包含column IN (v1, v2, ...)isNull / isNotNull空值判断column IS NULLorderByAsc / orderByDesc排序ORDER BY column ASC/DESC用LambdaQueryWrapper有个巨大的好处你如果写Device::getDeivceName注意我故意写错了IDE 直接标红编译报错。而用QueryWrapper写字符串deivce_name拼错了要到运行时才发现——运维同学半夜又要爬起来。五、分页插件告别手算 SQL Limit业务中分页是刚需。手写分页 SQL 不复杂但每次都拼LIMIT offset, size着实无聊。而且除了数据还要查总条数两条 SQL 来回写。MP 的分页插件一步到位ConfigurationpublicclassMybatisPlusConfig{BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptorinterceptornewMybatisPlusInterceptor();// 分页插件interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));returninterceptor;}}然后业务代码// 构建分页对象第1页每页10条PageDevicepagenewPage(1,10);// 加上条件LambdaQueryWrapperDevicewrappernewLambdaQueryWrapperDevice().eq(Device::getStatus,1)// 只要在线设备.orderByDesc(Device::getUpdateTime);// 执行分页查询PageDeviceresultdeviceMapper.selectPage(page,wrapper);System.out.println(当前页result.getCurrent());System.out.println(总页数result.getPages());System.out.println(总记录result.getTotal());System.out.println(数据列表result.getRecords());一条selectPage调用内部自动执行两条 SQLSELECT COUNT(*) FROM t_device WHERE status 1→ 查总数SELECT * FROM t_device WHERE status 1 ORDER BY update_time DESC LIMIT 0, 10→ 查分页数据你再也不用自己写两个查询方法了。六、自动填充createTime/updateTime 不用手动设后台管理系统里几乎所有表都有create_time和update_time每次新增或更新都要手动setCreateTime(now)麻烦且容易忘。MP 的自动填充功能专门解决这个问题ComponentpublicclassMyMetaObjectHandlerimplementsMetaObjectHandler{OverridepublicvoidinsertFill(MetaObjectmetaObject){this.strictInsertFill(metaObject,createTime,LocalDateTime.class,LocalDateTime.now());this.strictInsertFill(metaObject,updateTime,LocalDateTime.class,LocalDateTime.now());}OverridepublicvoidupdateFill(MetaObjectmetaObject){this.strictUpdateFill(metaObject,updateTime,LocalDateTime.class,LocalDateTime.now());}}配合实体类上的注解TableField(fillFieldFill.INSERT)privateLocalDateTimecreateTime;TableField(fillFieldFill.INSERT_UPDATE)privateLocalDateTimeupdateTime;之后你 insert/update 实体对象时根本不用管时间字段MP 在 SQL 执行前自动帮你填上。妈妈再也不用担心我看到createTime null的报错了。七、逻辑删除假删除真安全项目里几乎没有人敢直接DELETE FROM t_device WHERE id 1——数据丢了找不回来审计也过不了。常规操作是加一个is_deleted字段删的时候设1查的时候带WHERE is_deleted 0。但每个查询都要记得加这个条件烦不烦MP 帮你做了TableLogicprivateIntegerisDeleted;全局配置mybatis-plus:global-config:db-config:logic-delete-field:is_deletedlogic-delete-value:1# 已删除logic-not-delete-value:0# 未删除效果deviceMapper.deleteById(1L)→ 实际执行UPDATE t_device SET is_deleted 1 WHERE id 1所有select操作自动追加WHERE is_deleted 0需要查已删除数据用deviceMapper.selectList(...)加上.eq(Device::getIsDeleted, 1)即可注意逻辑删除和唯一索引有冲突。比如设备编号device_sn设了唯一键逻辑删除后新建一条相同编号的记录会失败。这时要么不用唯一索引要么把is_deleted也纳入唯一索引。八、乐观锁并发场景的数据安全保障无人售货柜的场景管理员 A 看到某设备信息在编辑管理员 B 也在同一时刻编辑同一台设备。A 点保存B 也点保存——后保存的把先保存的覆盖了这就是典型的丢失更新问题。乐观锁的解决思路在表中加一个version字段每次更新时带上版本号比对版本号匹配才更新同时版本号 1。VersionprivateIntegerversion;需要配置一个拦截器BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptorinterceptornewMybatisPlusInterceptor();interceptor.addInnerInterceptor(newOptimisticLockerInnerInterceptor());returninterceptor;}实际执行的 SQL 会变成UPDATEt_deviceSETdevice_name新名称,version3WHEREid1ANDversion2如果version已经被别人更新成了 3这条 SQL 影响行数为 0MP 会抛出OptimisticLockException上游捕获后提示数据已被他人修改请刷新重试——完美。九、完整实战无人售货柜设备管理把上面的功能串成一份完整的设备管理代码。Service 层publicinterfaceDeviceServiceextendsIServiceDevice{PageDevicepageSearch(Stringkeyword,Integerstatus,intpageNum,intpageSize);booleanonline(Longid);// 设备上线booleanoffline(Longid);// 设备离线}ServicepublicclassDeviceServiceImplextendsServiceImplDeviceMapper,DeviceimplementsDeviceService{OverridepublicPageDevicepageSearch(Stringkeyword,Integerstatus,intpageNum,intpageSize){LambdaQueryWrapperDevicewrappernewLambdaQueryWrapper();if(StringUtils.hasText(keyword)){wrapper.and(w-w.like(Device::getDeviceName,keyword).or().like(Device::getDeviceSn,keyword));}if(status!null){wrapper.eq(Device::getStatus,status);}wrapper.orderByDesc(Device::getUpdateTime);returnthis.page(newPage(pageNum,pageSize),wrapper);}Overridepublicbooleanonline(Longid){DevicedevicenewDevice();device.setId(id);device.setStatus(1);returnthis.updateById(device);}Overridepublicbooleanoffline(Longid){DevicedevicenewDevice();device.setId(id);device.setStatus(0);returnthis.updateById(device);}}Controller 层RestControllerRequestMapping(/api/device)publicclassDeviceController{AutowiredprivateDeviceServicedeviceService;GetMapping(/page)publicResultPageDevicepage(RequestParam(requiredfalse)Stringkeyword,RequestParam(requiredfalse)Integerstatus,RequestParam(defaultValue1)intpageNum,RequestParam(defaultValue10)intpageSize){returnResult.success(deviceService.pageSearch(keyword,status,pageNum,pageSize));}PostMapping(/{id}/online)publicResultVoidonline(PathVariableLongid){returndeviceService.online(id)?Result.success():Result.fail(操作失败);}PostMapping(/{id}/offline)publicResultVoidoffline(PathVariableLongid){returndeviceService.offline(id)?Result.success():Result.fail(操作失败);}}ServiceImplT是 MP 提供的通用 Service 实现继承了它就有了全套save、remove、update、page、list等方法。你只需要在它上面补几行自定义逻辑就行。总结MyBatis-Plus 的正确使用姿势总结Mapper 继承BaseMapperT单表 CRUD 自由了不用写一行 SQL条件查询用LambdaQueryWrapper编译期保证字段名正确杜绝 runtime 翻车分页用PaginationInnerInterceptor一行selectPage搞定连总数都帮你算了自动填充用MetaObjectHandler时间字段从此无人值守逻辑删除 乐观锁数据安全的两大护法简单注解就搞定MP 不是替代 MyBatis而是让它更好用。复杂联表查询、存储过程这些XML 照样上但 80% 的单表操作场景MP 让你把开发效率拉满。

相关新闻

2026/8/21 21:58:15

常见电路设计——(1)超级电容充电电路

目录 整体电路架构 一、恒流主回路器件(CC 阶段核心) 1. R500、R501(恒流采样电阻) 2. T501(主功率调整管) 3. T500(电流检测 / 负反馈管) 4. R502(基极限流电阻) 二、恒压控制环路器件(CV 阶段核心) 1. U500(TL431,精密基准源) 2. T502(电压环误差放…

2026/8/22 0:49:48

三步完成ncmdumpGUI:NCM转MP3免费开源工具完整攻略

三步完成ncmdumpGUI:NCM转MP3免费开源工具完整攻略 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 刚充了会员下的歌,拷到 U 盘往车机一…

2026/8/22 0:49:48

数学建模实战:TextBlob与SnowNLP情感分析工具对比与应用

1. 项目概述:从数学建模到情感计算最近在整理数学建模的备赛笔记,翻到情感分析这个主题时,感触颇深。很多初次接触数学建模的同学,一看到“情感计算”、“文本挖掘”这类词,第一反应就是“这得用多复杂的算法啊&#x…

2026/8/22 0:49:48

从零构建分布式任务流:基于Deer-Flow的ETL与自动化通知实践

在实际分布式任务调度和数据处理场景中,我们经常面临任务编排复杂、依赖管理困难、监控运维不便等痛点。一个设计良好的任务流引擎能够将分散的任务节点串联成清晰的工作流,实现任务的自动化、可视化和可观测执行。字节跳动开源的 Deer-Flow 正是这样一个…

2026/8/22 0:49:48

2026陇南危房鉴定检测怎么选?老旧房危房鉴定靠谱机构 TOP 结构安全检测+ 报告可查 电话汇总

陇南街头巷尾的老旧小区、乡镇自建房、沿街商铺乃至工业园区厂房,眼下正面临危房鉴定检测的刚性需求。市面上危房鉴定机构虽多,但资质不全、报告无效的乱象屡见不鲜,不少业主费时费力却拿到无法通过住建审核的无效文件。小编实地走访筛选本地…

2026/8/21 13:13:49

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/21 20:14:07

工业传感器与变送器详解:序章 从物理世界到工业数据

序章 从物理世界到工业数据 ——重新认识工业传感器与变送器 工业自动化系统正变得日益复杂。今天的工业现场早已不是简单的控制回路,而是由多层技术共同构成的立体体系:PLC、DCS、SCADA、MES、工业互联网、边缘计算与人工智能。控制系统可以执行复杂算法,工业网络可以实现…

2026/8/21 15:40:01

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/21 15:40:01

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/21 0:31:27

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…