Skip to content

开篇——为什么手写 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. 阅读准备

  1. 了解 MyBatis 的 #{} / ${}resultMap 基本用法
  2. 手边放一份自己的 *Mapper.xml,边读边改,效果最好
  3. 有 MySQL 环境可用 EXPLAIN 验证性能类改造

7. 注意事项

  1. 改 SQL 要配回归测试。尤其 select * 改显式列、Wrapper 重写,用同一组入参对比新旧结果是否一致
  2. 别一次性大改。按注入 → 反模式 → 性能 → 冗余逐个推进,改完确认 MyBatis 能正常解析 XML
  3. MyBatis-Plus 内置方法是误报重灾区。selectById/insert 等由框架提供、没有 XML,自查脚本会把它误报成缺实现,需人工过滤或加入忽略清单

8. 总结

维度无意识手写学完本系列后
安全性${} 裸拼风险未知参数化 + 白名单
性能慢查询随机爆发索引友好 + 分页
可维护性反模式散落显式列 + 干净 XML
知识靠个人经验可复用的方法论

下一篇直击最高危的一类:SQL 注入。我们用一张图看清攻击是怎么发生的,并给出白名单改造的完整代码。