开篇——为什么手写 SQL 值得专门写一篇系列
技术栈:Spring Boot + MyBatis + MyBatis-Plus + MySQL 适合谁读:想系统搞懂手写 Mapper SQL 常见隐患,并建立一套可复用优化思路的开发者
1. 为什么是手写 SQL
MyBatis 和很多 ORM 不一样:它不帮你生成 SQL,只负责把你写的 SQL 和 Java 对象绑在一起。这带来很大自由,但也意味着 SQL 对不对、安不安全、快不快,全靠写代码的人自己负责。
在典型的物联网平台里,数据访问层通常同时有两套写法:
- MyBatis-Plus 的
BaseMapper:单表增删改查运行时自动生成,开发者基本不写 SQL - 手写
*Mapper.xml:凡是多表关联、统计聚合、动态列、批量写入,都得自己拼 SQL
问题就出在第二套。手写 SQL 没有编译期检查,IDE 对 XML 里的 SQL 也只是高亮一下,不会告诉你写错了。一个 ${}、一个 select *、一个漏掉的 limit,编译时一切正常,只有等到线上出问题才暴露。
2. 这几类问题有什么关系
你可能会问:SQL 注入、select *、慢查询、死代码,看起来风马牛不相及,为什么要放在一个系列里讲?
因为它们有一个共同根源:手写 SQL 把控制权完全交给了开发者。开发者在赶工期、写动态 SQL、图省事时,容易在不同维度上翻车。
text
手写 SQL 的隐患,按危害类型分成三条线:
安全线 → SQL 注入(最危险,能拖库)
性能线 → select *、慢查询(悄悄变慢,拖垮数据库)
维护线 → 死代码、接口对不上(越积越乱,埋雷)
它们不是孤立的:死代码里可能藏着注入点,select * 又会拖慢性能。
所以系列按从最危险到最隐蔽的顺序讲:注入 → select * → 性能 → 死代码。3. 五类隐患全景图
text
手写 Mapper SQL 的常见隐患
├── 安全:SQL 注入
│ ├── #{} 与 ${} 混淆
│ └── 动态列名/排序裸拼外部输入
├── 反模式:SELECT *
│ ├── 多表同名列覆盖
│ └── 无法走覆盖索引
├── 性能:慢查询反模式
│ ├── LIKE 前导通配
│ ├── ORDER BY 无 LIMIT
│ └── GROUP BY 列过多 / 深分页
├── 冗余:死代码
│ ├── XML 注释死代码
│ └── 孤儿语句
└── 一致性:接口与 XML 不匹配
├── XML 有接口无
└── 接口有 XML 无4. 本系列学习路线
| 篇 | 主题 | 你会学到 |
|---|---|---|
| 一(本篇) | 开篇与全景 | 手写 SQL 为何易出问题、五类隐患地图 |
| 二 | SQL 注入 | #{} 预编译原理、${} 的正确打开方式、白名单校验 |
| 三 | SELECT * 反模式 | 列覆盖、覆盖索引、Base_Column_List 改造 |
| 四 | 性能反模式 | 前导通配、分页、GROUP BY、深分页与延迟关联 |
| 五 | 死代码与一致性 | 冗余 Mapper 识别清理、接口/XML 双向校验 |
5. 一个顺手的自查思路
与其等出问题再救火,不如给项目做个轻量体检。不需要复杂工具,一个几十行的脚本就能扫出大部分问题:
- 遍历
*/src/main/resources/mapper/**/*Mapper.xml - 用正则匹配反模式特征:
SELECT *、${}、LIKE '%...%'、ORDER BY后没LIMIT等 - 把 XML 语句
id和*Mapper.java接口方法做双向比对,找出孤儿语句和缺实现
这类脚本的价值不在于找出多少处,而在于帮你看清全貌,让整改有章法。白名单工具的完整代码见附录:SqlWhitelistValidator 完整代码。
6. 阅读准备
- 了解 MyBatis 的
#{}/${}与resultMap基本用法 - 手边放一份自己的
*Mapper.xml,边读边改,效果最好 - 有 MySQL 环境可用
EXPLAIN验证性能类改造
7. 注意事项
- 改 SQL 要配回归测试。尤其
select *改显式列、Wrapper 重写,用同一组入参对比新旧结果是否一致 - 别一次性大改。按注入 → 反模式 → 性能 → 冗余逐个推进,改完确认 MyBatis 能正常解析 XML
- MyBatis-Plus 内置方法是误报重灾区。
selectById/insert等由框架提供、没有 XML,自查脚本会把它误报成缺实现,需人工过滤或加入忽略清单
8. 总结
| 维度 | 无意识手写 | 学完本系列后 |
|---|---|---|
| 安全性 | ${} 裸拼风险未知 | 参数化 + 白名单 |
| 性能 | 慢查询随机爆发 | 索引友好 + 分页 |
| 可维护性 | 反模式散落 | 显式列 + 干净 XML |
| 知识 | 靠个人经验 | 可复用的方法论 |
下一篇直击最高危的一类:SQL 注入。我们用一张图看清攻击是怎么发生的,并给出白名单改造的完整代码。