人生第一次线上 OOM 事故,竟和 where 1 = 1 有关

这篇文章,聊聊一个大家经常使用的编程模式 :Mybatis +「where 1 = 1 」。

笔者人生第一次重大的线上事故 ,就是和使用了类似的编程模式 相关,所以印象极其深刻。

这几天在调试一段业务代码时,又遇到类似的问题,所以笔者觉得非常要必要和大家絮叨絮叨。

1 OOM 事故

笔者曾服务一家电商公司的用户中心,用户中心提供用户注册,查询,修改等基础功能 。用户中心有一个接口 getUserByConditions ,该接口支持通过 「用户名」、「昵称」、「手机号」、「用户编号」查询用户基本信息。

我们使用的是 ibatis (mybatis 的前身), SQLMap 见上图 。当构建动态 SQL 查询时,条件通常会追加到 WHERE 子句后,而以 WHERE 1 = 1 开头,可以轻松地使用 AND 追加其他条件。

但用户中心在上线后,竟然每隔三四个小时就发生了内存溢出问题 ,经过通过和 DBA 沟通,发现高频次出现全表查询用户表,执行 SQL 变成 :

查看日志后,发现前端传递的参数出现了空字符串 ,笔者在代码中并没有做参数校验,所以才出现全表查询 ,当时用户表的数据是 1000万 ,调用几次,用户中心服务就 OOM 了。

笔者在用户中心服务添加接口参数校验 ,即:「用户名」、「昵称」、「手机号」、「用户编号」,修改之后就再也没有产生这种问题了。

2 思维进化

1、前后端同时做接口参数校验

为了提升开发效率,我们人为的将系统分为前端、后端,分别由两拨不同的人员开发 ,经常出现系统问题时,两拨人都非常不服气,相互指责。

有的时候,笔者会觉得很搞笑,因为这个本质是个规约问题。

要想系统健壮,前后端应该同时做接口参数校验 ,当大家都遵循这个规约时,出现系统问题的风险大大减少。

2、复用和专用要做平衡

笔者写的这个接口 getUserByConditions ,支持四种不同参数的查询,但是因为代码不够严谨,导致系统出现 OOM 。

其实,在业务非常明确的场景,我们可以将复用接口,拆分成四个更细粒度的接口 :

  • 按照用户 ID 查询用户信息
  • 按照用户昵称查询用户信息
  • 按照手机号查询用户信息
  • 按照用户名查询用户信息

比如按照用户 ID 查询用户信息 , SQLMAP 就简化为:

通过这样的拆分,我们的接口设计更加细粒度,也更容易维护 , 同时也可以规避 where 1 =1 产生的问题。

有的同学会有疑问:假如拆分得太细,会不会增加我编写 接口和 SQLMap 的工作量 ?

笔者的思路是:通过代码生成器动态生成,是绝对可以做到的 ,只不过需要做一丢丢的定制。

3、编写代码时,需要考虑资源占用量,做好预防性编程

笔者刚入行的时候,只是机械性的完成任务,并没有思考代码后面的资源占用,以及有没有可能产生恶劣的影响。

随着见识更多的系统,学习开源项目,笔者慢慢培养了一种习惯:

  • 这段代码会占用多少系统资源
  • 如何规避风险 ,做好预防性编程。

其实,这和玩游戏差不多 ,在玩游戏的时,我们经常说一个词,那就是意识。

上图,后裔跟墨子在压对面马可蔡文姬,看到小地图中路铠跟小乔的视野,方向是往下路来的,这时候我们就得到了一个信息。

知道对面的人要来抓,或者是协防,这种情况我们只有两个人,其他的队友都不在,只能选择避战,强打只会损失两名"大将"。

通过小地图的信息,并且想出应对方法,就是叫做"猜测意识"。

编程也是一样的,我们思考代码可能产生的系统资源占用,以及可能存在的风险,并做好防御性编程,就是编程的意识

4 写到最后

当我们在使用 :Mybatis +「where 1 = 1 」编程模式时,需要如下三点:

  1. 前后端同时做好接口参数校验 ;
  2. 复用和专用要做平衡,条件允许情况下将复用 SQLMap 拆分成更细粒度的 SQLMap ;
  3. 编写代码时,需要考虑资源占用量,做好预防性编程 ;

文章片段推荐:

生命就是这样一个过程,一个不断超越自身局限的过程,这就是命运,任何人都是一样,在这过程中我们遭遇痛苦、超越局限、从而感受幸福。

所以一切人都是平等的,我们毫不特殊。

--- 史铁生


任何问题都欢迎加勇哥 wx:zhangyongtaozhe

公Z号:勇哥Java实战 (关注并回复:mq,即可获取勇哥编写的《RocketMQ4.X设计精要》电子书和 B站全部视频课件 PPT )

相关推荐
leobertlan7 小时前
2025年终总结
前端·后端·程序员
面向Google编程8 小时前
从零学习Kafka:数据存储
后端·kafka
易安说AI8 小时前
Claude Opus 4.6 凌晨发布,我体验了一整晚,说说真实感受。
后端
易安说AI8 小时前
Ralph Loop 让Claude无止尽干活的牛马...
前端·后端
易安说AI9 小时前
用 Claude Code 远程分析生产日志,追踪 Claude Max 账户被封原因
后端
颜酱10 小时前
图结构完全解析:从基础概念到遍历实现
javascript·后端·算法
Coder_Boy_12 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
掘金者阿豪13 小时前
关系数据库迁移的“暗礁”:金仓数据库如何规避数据完整性与一致性风险
后端
ServBay13 小时前
一个下午,一台电脑,终结你 90% 的 Symfony 重复劳动
后端·php·symfony
sino爱学习13 小时前
高性能线程池实践:Dubbo EagerThreadPool 设计与应用
java·后端