我们提供安全,免费的手游软件下载!
在本文中,我想和大家分享一个经常应用的编程模式:Mybatis +「where 1 = 1」。这个模式在开发中经常使用,然而我个人却因为这种模式经历过一次线上事故,让我对它留下了深刻印象。
这几天,当我在调试业务代码时,又一次遇到了类似的问题。因此,我认为有必要和大家分享我的经验教训。
1. OOM 事故
在过去,我曾服务一家电商公司的用户中心,该用户中心提供用户注册、查询、修改等基础功能。其中有一个名为 getUserByConditions 的接口,它支持通过 「用户名」、「昵称」、「手机号」和「用户编号」来查询用户的基本信息。
我们使用的是 ibatis(mybatis 的前身),SQLMap 如上图所示。在构建动态 SQL 查询时,通常会将条件追加到
WHERE
子句后。而使用
WHERE 1 = 1
开头,可以轻松地使用
AND
来追加其他条件。
但在用户中心上线后,每隔三四个小时就会发生内存溢出问题。通过与 DBA 沟通,发现高频次出现全表查询用户表的情况,执行的 SQL 变成了:
查看日志后,我们发现前端传递的参数中存在空字符串。由于我在代码中并没有进行参数校验,因此导致了全表查询。当时,用户表的数据量达到了1000万,只需几次这样的调用,用户中心服务就会发生内存溢出。我随后在用户中心服务中添加了接口参数校验,即验证「用户名」、「昵称」、「手机号」和「用户编号」。自此之后,我们再也没有遇到过类似的问题。
2. 思维进化
1)前后端同时做接口参数校验
为了提升开发效率,我们人为地将系统分为前端和后端,分别由两组不同的人员开发。然而,通常情况下当系统出现问题时,两组人员都非常不服气,相互指责。
有时,我会觉得很搞笑,因为这本质上是个规约问题。
要使系统更加健壮,前后端应该同时进行接口参数校验。只有在大家都遵循这个规约的时候,系统出现问题的风险才会大大降低。
2)复用和专用要做平衡
我编写的接口 getUserByConditions,支持四种不同参数的查询。然而,由于代码不够严谨,导致系统出现了 OOM 问题。
在业务非常明确的场景下,我们其实可以将复用接口拆分为四个更细粒度的接口:
例如,按照用户 ID 查询用户信息的 SQLMap 如下所示:
通过这种拆分,我们的接口设计变得更加细粒度,也更容易维护,同时也可以规避由"where 1 = 1"产生的问题。
有些同学可能会有疑问:假如拆分得太细,会不会增加接口和 SQLMap 的编写工作量?
我的看法是:我们可以通过代码生成器动态生成,这是可以做到的,只需要进行轻微的定制。
3)编写代码时,需要考虑资源占用量,做好预防性编程
我刚入行的时候,只是机械性地完成任务,并没有考虑代码后面可能占用的资源,也没有思考其可能产生的恶劣影响。
随着更多的系统经验和对开源项目的学习,我慢慢养成了一种习惯:
其实,这和玩游戏差不多。在玩游戏的时候,我们经常说一个词,那就是 「意识」 。
上图中,后裔跟墨子在压对面马可蔡文姬,通过小地图中路铠跟小乔的视野,我们可以判断他们是往下路来的。这时候我们就得到了一个信息。
知道对面的人要来抓,或者是协防,这种情况我们只有两个人,其他的队友都不在,只能选择避战,强打只会损失两名“大将”。
通过小地图的信息,并且设想出应对方法,这就是 「猜测意识」 。
编程也一样,我们需要思考代码可能产生的系统资源占用,以及可能存在的风险,并采取预防性编程来对抗这种情况,这就是 编程的意识 。
4. 写到最后
在使用 Mybatis +「where 1 = 1」编程模式时,我们需要注意以下三点:
文章片段推荐:
生命就是这样一个过程,一个不断超越自身局限的过程,这就是命运,任何人都是一样,在这过程中我们遭遇痛苦、超越局限、从而感受幸福。
所以一切人都是平等的,我们毫不特殊。
--- 史铁生
如果我的文章对你有所帮助,请帮忙 点赞、在看、转发 一下。你的支持会激励我输出更高质量的文章,非常感谢!
热门资讯