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

2026年了,还在手写SQL?我整理了5个让MyBatis-plus失效的场景。

团队去年全面切MyBatis-plus,想着CRUD不用写了,效率翻倍。结果半年后,复杂业务场景里还是手写SQL,而且比原来更绕。整理了5个让MyBatis-plus"失效"的场景,不是框架不好,是用错了地方。

场景一:多层嵌套子查询

MyBatis-plus的QueryWrapper链式调用,两层嵌套还能看,三层以上就是灾难

// 两层勉强能读 queryWrapper.eq("status",1).in("id", new QueryWrapper<Order>().select("user_id").eq("amount",100));// 三层?我放弃了,直接写XML

实际业务:查"最近30天消费超过500元且购买过指定品类且退货率低于10%的用户"。三层子查询+聚合+条件,QueryWrapper写出来像天书,维护的人骂娘。

手写SQL:

<selectid="findQualifiedUsers"resultType="User">SELECT u.* FROM user u WHERE u.id IN(SELECT o.user_id FROM`order`o WHERE o.create_time>DATE_SUB(NOW(), INTERVAL30DAY)AND o.amount>500AND o.id IN(SELECT oi.order_id FROM order_item oi WHERE oi.category_id=#{categoryId})AND o.user_id NOT IN(SELECT r.user_id FROM refund r WHERE r.rate>0.1))</select>

看着长,但结构清晰,SQL优化器也能看懂。MyBatis-plus生成的SQL,三层嵌套后逻辑混乱,执行计划全表扫描。

场景二:动态表名/动态列

分库分表场景,表名按月份拆分: order_202601 、 order_202602 。

MyBatis-plus的 @TableName 注解不支持动态表名,除非自己写拦截器替换SQL,但那样还不如直接写XML。

<selectid="statReport"resultType="Map">SELECT province, city, channel, DATE(create_time)as dt, COUNT(*)as order_cnt, SUM(amount)as total_amount, AVG(amount)as avg_amount, SUM(CASE WHENstatus=9THEN1ELSE0END)/COUNT(*)as refund_rate FROM`order`<where><iftest="province != null">AND province=#{province}</if><iftest="startDate != null">AND create_time>=#{startDate}</if></where>GROUP BY province, city, channel, DATE(create_time)WITH ROLLUP</select>

WITH ROLLUP 做维度汇总,MyBatis-plus不支持这种语法,只能原生SQL。

场景四:批量插入优化

MyBatis-plus的 saveBatch 默认是一条条INSERT,批量1000条数据,数据库往返1000次。

// 默认实现,性能极差 userService.saveBatch(userList);//1000次网络往返

想优化?自己写 INSERT INTO … VALUES (…), (…), (…) ,或者配置 rewriteBatchedStatements=true ,但MyBatis-plus不帮你做这个。

手写SQL:

<insertid="batchInsert">INSERT INTO user(name, email, create_time)VALUES<foreachcollection="list"item="item"separator=",">(#{item.name}, #{item.email}, NOW())</foreach></insert>

一次网络往返,性能提升100倍。

场景五:数据库特定语法

MySQL的 ON DUPLICATE KEY UPDATE 、PostgreSQL的 ON CONFLICT 、SQL Server的 MERGE ,MyBatis-plus的通用CRUD不支持这些方言。

<insertid="upsert">INSERT INTO user(id, name, email)VALUES(#{id}, #{name}, #{email})ON DUPLICATE KEY UPDATE name=VALUES(name), email=VALUES(email), update_time=NOW()</insert>

我的用法
不是不用MyBatis-plus,是分层用:

简单CRUD、单表查询、快速原型:MyBatis-plus,省代码

复杂查询、子查询、聚合、批量、方言特性:手写XML,可控可优化

一个反直觉的结论

MyBatis-plus最大的价值,不是让你不写SQL,是让你明确知道哪些SQL不用写。简单场景省时间,复杂场景不折腾,边界清晰。
如果所有SQL都手写,和MyBatis有什么区别?如果所有SQL都用MyBatis-plus,复杂业务就是灾难。

最后说个数据

我们团队代码统计:MyBatis-plus占60%,手写XML占40%。但Bug率,手写XML的部分反而更低,因为复杂逻辑显式表达,review时容易发现问题。MyBatis-plus生成的SQL,有时候执行计划全表扫描,直到线上慢查询才发现。

工具是帮你省时间的,不是帮你思考的。复杂场景,手写SQL是负责任的选择。

http://www.cnnetsun.cn/news/3020764.html

相关文章:

  • 终极指南:用Deep3D将2D视频瞬间变成立体3D大片
  • 企业级应用权限绕过漏洞剖析:从原理到实战复现
  • 宝可梦移动端存档编辑器PKHeX.Mobile:新手快速上手完整指南
  • 10分钟快速上手:RVC语音克隆与实时变声完整指南
  • qmc-decoder终极指南:如何快速解密QQ音乐加密文件,解锁你的音乐自由
  • VMware Unlocker终极指南:3分钟解锁macOS虚拟机隐藏功能
  • SQL注入WAF绕过实战:从基础混淆到协议层攻击的攻防博弈
  • 现代Windows上如何让经典游戏重获联机能力?IPXWrapper终极解决方案揭秘
  • Cpp2IL终极指南:如何轻松逆向Unity IL2CPP二进制文件
  • 昆明 AI 推广现状浅析:本土 GEO 服务机构塔米德运营模式分享
  • KMS智能激活终极指南:5分钟免费激活Windows和Office
  • 二手萨姆肯 SAMCO RIE-300NR 反应离子刻蚀系统技术规格详解
  • 如何高效使用 dnSpyEx:专业开发者的 .NET 调试与反编译实用指南
  • 2026年B2B外贸获客工具选型指南:适配全场景数字化拓客路径
  • IPXWrapper终极指南:3步让经典游戏在现代Windows上重生联机功能
  • TQVaultAE:泰坦之旅周年版的终极物品管理解决方案,告别背包空间不足的烦恼!
  • 南瓜书:帮你看懂西瓜书里那些跳过的公式
  • Python GPIO Zero硬件控制入门:从LED闪烁到按钮交互实战
  • BurpSuite插件log4j2Scan实战:自动化Log4Shell漏洞检测与利用
  • 树莓派视频硬件解码许可机制与编解码器支持全解析
  • 告别Windows激活烦恼:智能脚本让系统授权变得简单
  • 预编译防SQL注入原理详解:从数据库驱动到实战应用
  • 中小企业使用经销商管理系统能带来哪些好处?
  • 适合自媒体新手的短视频配音工具有哪些
  • 资源下载神器:5分钟搞定全网视频音频快速保存
  • 【2023虚拟机软件终极横评】:VMware、VirtualBox、Hyper-V、Parallels四大平台性能/兼容/安全实测数据全公开
  • 鸿蒙 ArkUI 入门:@State 状态与 Stack 层叠布局详解(附同心圆实战)
  • 别再拼凑教程了!Claude Code for macOS完整安装配置,环境+接口一篇搞定
  • 工业照明选型技术总结:吸顶灯、V5、应急灯、TT69、TH款工况适配分析
  • 企业微信OAuth2.0免登授权链路真的安全吗?怎么防止授权码泄露与篡改?