死代码与接口一致性——冗余 Mapper 的识别与清理
技术栈:MyBatis + MyBatis-Plus 适合谁读:需要清理 XML 死代码、保持 Mapper 接口与 XML 一一对应的开发者
1. 问题背景
前面几篇讲活着的的问题 SQL。还有一类容易被忽视:死代码,XML 里被注释掉的语句、没人调用的孤儿语句,以及接口与 XML 对不上。它们不执行,却会误导维护者、干扰自查、甚至藏着未被发现的注入点。
2. 死代码是怎么来的
- 重构遗留:旧语句被新写法替代后,原作者用
<!-- -->把旧版注释在旁边备个份,结果一留就是两年 - 试错残留:调试时复制一份改着试,试成功的留下来,失败的变成注释躺在那
- 接口删了 XML 没删:接口方法改名或删除后,XML 里的
<select id="...">没同步删,成了孤儿
危害不在于执行,而在于:
- 污染自查:扫描工具会把注释里的
${}也算进去,虚报风险、分散注意力 - 误导维护:新人看到两段相似 SQL,分不清哪段在用,改错对象
- 藏污纳垢:被注释或孤立的语句里可能藏着含
${}的注入写法,它暂时没被调用不代表永远安全
3. 接口一致性模型
MyBatis 要求 XML 语句的 id 和 Mapper 接口方法一一对应。这是个双向关系,哪边失衡都会出问题:
text
理想: Mapper 接口方法 <── id 一一对应 ──> XML 语句
失衡的两种情况:
· XML 有 / 接口无 → 孤儿语句(多半是死代码)
· 接口有 / XML 无 → 缺实现(运行报 BindingException)MyBatis-Plus 的内置方法,selectById、insert、updateById 等,由框架运行时提供,本来就没有 XML。自查脚本不认识就会把它误报成缺实现,这类清单必须人工复核或加入忽略清单,不能直接删。
4. 如何识别与清理
4.1 找到死代码
- 注释死代码:在 XML 中搜
<!--包裹的<select>/<update>等标签 - 孤儿语句:把每个 XML
id和接口方法名比对,接口里没有的就是候选
4.2 删除注释死代码
确认新版本已上线、旧版无人引用后,直接删掉整段注释。保留方式应交给 Git 历史,而不是躺在 XML 里。
xml
<!-- 旧代码(已删除):被新实现替代,仅留 Git 历史 -->
<!--
<select id="queryById" resultMap="BaseResultMap">
select * from operation_log where id = #{id}
</select>
-->4.3 核实孤儿语句
对每个 XML 有、接口无的 id,全局搜引用:
- 有调用方但接口签名不匹配 → 修正接口
- 全仓无引用 → 确认是死代码,删除
4.4 核实缺实现
对每个接口有、XML 无的方法:
- 是 MyBatis-Plus 内置 → 标记为误报,忽略
- 是手写的 → 补 XML 实现,否则运行时会
BindingException
4.5 用脚本持续校验
把自查脚本纳入 CI,每次提交都重跑,确保注入点、孤儿语句不新增。
5. 清理对照
| 现象 | 处理 |
|---|---|
| XML 注释掉的旧语句 | 确认新版在用 → 删注释,Git 留痕 |
| XML 有 / 接口无 | 搜引用,无引用则删 XML |
| 接口有 / XML 无(手写) | 补 XML 实现 |
| 接口有 / XML 无(MP 内置) | 标记误报,忽略 |
6. 注意事项
- 删之前先全局搜引用。尤其
@Select注解、Service 里按名调用的地方,确认零引用再删,避免编译或运行报错 - MyBatis-Plus 误报要白名单化。把
selectById/insert/...等内置方法加入脚本忽略清单,减少人工复核噪音 - XML 解析测试兜底。删除或改动后,用
SqlSessionFactoryBuilder加载全部 mapper,验证 XML 无语法错误 - 改动同步接口。删 XML 语句时,记得同步删除或保留对应接口方法,保持一一对应
7. 总结
| 维度 | 改造前 | 改造后 |
|---|---|---|
| 死代码 | 注释残留 + 孤儿语句 | 删除,Git 留痕 |
| 注入隐患 | 藏在注释里的 ${} | 暴露并清除 |
| 一致性 | 接口/XML 不匹配噪音大 | 人工复核 + 脚本复跑 |
| 维护成本 | 新人分不清在用哪段 | 一份干净、对应明确的 XML |
至此,物联网平台 SQL 治理手记完结:从注入、SELECT *、性能反模式到死代码与一致性,每一类都顺着是什么、怎么来的、为什么、危害、如何解决讲清楚。把文中的思路跑起来,你的项目也能拥有一份干净、安全、高性能的 Mapper 层。