聊聊 Mybatis 动态 SQL

这篇文章,我们聊聊 Mybatis 动态 SQL  ,以及我对于编程技巧的几点思考 ,希望对大家有所启发。

图片

1 什么是 Mybatis 动态SQL

如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。

Mybatis  借助功能强大 OGNL 表达式,可以根据参数条件,动态生成执行 SQL 。

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。

图片

这条语句提供了可选的查询博客文章列表 ,如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 博客都会返回。

如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果。

如果希望通过 “title” 和 “author” 两个参数都可以搜索,只需要加入另一个条件即可,见下图:

图片

我们也可以使用 where 标签,该标签只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 标签也会将它们去除。

图片

Mybatis 还支持 choose (when, otherwise)、trim (where, set)、foreach 等其他的动态标签,这里就不一一赘述了。

2 人生第一次线上OOM事故

我曾服务一家电商公司的用户中心,用户中心提供用户注册,查询,修改等基础功能 。

那个时候 Dubbo 等 RPC 框架并没有开源,所有的服务都以 HTTP 接口形式提供,数据传输格式是 XML 。

因为写接口非常费劲,所以为了接口复用,我写了一个通用接口 getUserByConditions ,该接口支持通过 「用户名」、「昵称」、「手机号」、「用户编号」这三个查询用户基本信息。

使用的是 ibatis (mybatis 的前身), SQLMap 见下图 。

图片

当构建动态 SQL 查询时,条件通常会追加到 WHERE 子句后,而以 WHERE 1 = 1 开头,可以轻松地使用 AND 追加其他条件。

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

图片

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

最终解决问题的方式很简单,后端在接收参数时,做了参数校验。

事故虽然解决了,但对我的影响一直延续至今。我仍然记得当时站在运维同学旁边,不断的看他调整 JVM 参数 ,重启服务的画面,自己那个时候真的是羞愧难当,心中发誓:以后绝对不可以发生类似的事故

对于动态 SQL ,我的编程思维也经历了如下三个阶段 :

  • 前后端参数校验

  • 复用和专用要做平衡

  • 防御性编程意识

3 前后端参数校验

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

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

1、前端校验

图片

前端校验,主要是为了提高用户体验,例如用户输入一个邮箱地址,要校验这个邮箱地址是否合法,没有必要发送到服务端进行校验,直接在前端用 js 进行校验即可。

但是大家需要明白的是,前端校验无法代替后端校验,前端校验可以有效的提高用户体验,但是无法确保数据完整性,因为在 B/S 架构中,用户可以方便的拿到请求地址,然后直接发送请求,传递非法参数。

2、后端校验

后端必须做参数校验,后端必须做参数校验,后端必须做参数校验,重要的事情表达三次。

数据在网络传输过程中有可能被篡改了,或者数据不满足业务需求,假如不做后端参数校验,则有可能导致系统异常,或者业务出现重大事故。

比如在 SpringBoot 项目中,我们可以使用 hibernate-validator 进行参数校验 。

POST、PUT 请求一般会使用 requestBody 传递参数,这种情况下,后端使用 DTO 对象进行接收。

只要给 DTO 对象加上 @Validated 注解就能实现自动参数校验。比如,有一个保存 User 的接口,要求 userName 长度是 2-10,account 和 password 字段长度

是 6-20。

在 DTO 字段上声明约束注解:

图片

在方法参数上声明校验注解:

图片

虽然,我们可以使用接口校验,可以保证动态 SQL 的参数正确,但是假如我们仅仅只是复用 SQLMap (Dao 方法)时,也有可能因为调用方传递参数错误,导致非预期的问题。

当然,我们也可以使用 Mybatis 拦截器从根本上来解决,但是我想这样会加大系统的复杂度。于是,我思考了了另外一点:复用和专用要做平衡

4 复用和专用要做平衡

我当时写的那个接口 getUserByConditions ,是支持四种不同参数的查询,同样也是为了省时间,快点出活。

后来,随着我工作经验的日益丰富,我的编程习惯也慢慢发生了改变,对于业务需求明确的场景,我更多的倾向于将通用接口拆分成专用接口。

比如 getUserByConditions 可以拆分成如下四个接口 ,

  • 按照用户 ID 查询用户信息

  • 按照用户昵称查询用户信息

  • 按照手机号查询用户信息

  • 按照用户名查询用户信息

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

图片

通过这样的拆分,我们的接口设计更加细粒度,也更容易维护 , 同时也可以规避 where 1 =1 产生的不确定性(虽然我做了后端校验,依然存在不确定性)。

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

笔者的思路是:定制自己的代码生成器,将生成的 SQLMap  、Mapper 保证更细的颗粒度。

5 防御性编程意识

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

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

  • 这段代码会占用多少系统资源

  • 如何规避风险 ,做好预防性编程。

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

图片

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

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

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

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

6 写到最后

人生第一次线上 OOM 事故,因我在使用 Mybatis 动态 SQL 时,没有做后端校验而出现,造成了比较坏的影响。

在后面的职业生涯里面,为了规避生产环境的事故,我试着打磨自己的编程思维,比如做好后端校验平衡好复用和专用接口培养防御性编程的意识 。

絮絮叨叨这么多,大家可能觉得我小题大做了,但事实是,类似我这样的事故层出不穷,上周我又目睹了一起。

IT 世界有了那么多框架,好像我们依然写不好代码,我有点沮丧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/30091.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何设置文件夹密码?文件夹加密如何操作!分享4款安全加密软件!

在数字化时代,数据安全显得尤为重要。设置文件夹密码和加密操作是保护个人或企业数据不被非法访问的有效手段。本文将为您详细介绍如何设置文件夹密码和加密操作,并分享四款安全加密软件,助您轻松提升数据安全防护能力。 一、如何设置文件夹/…

工作人员能从轧钢测径仪上获取哪些有效信息?

轧钢测径仪安装在轧钢生产线中,无论是热轧还是冷轧,都不能阻挡测径仪的高速无损高精检测。它采用八轴测量系统,能全方位检测外径尺寸,并且配备了测控软件系统,为工作人员提供更加丰富的产线信息。 普通轧钢测径仪能获…

Playwright 入门教程

1. 环境说明 操作系统:macOS 11.7Python:3.10.6 2. 安装 2.1. 创建测试环境 mkdir playwright-demo cd playwright-demo/ python3 -m venv venv # 安装 Pytest 插件 venv/bin/pip3 install pytest-playwright # 安装需要的浏览器 venv/bin/playwrigh…

DLP数据防泄密系统有什么功能?四款特别好用的DLP仿泄密系统

DLP(Data Loss Prevention,数据丢失防护)系统是一类专门用于保护组织内部数据不被非法访问、泄露或误用的安全解决方案。 这类系统通常具备以下关键功能: 1.数据识别与分类:自动发现并分类存储在网络、终端和云环境中…

24计算机应届生的活路是什么

不够大胆❗ 很多小伙伴在找工作时觉得自己没有竞争力,很没有自信,以至于很害怕找工作面试,被人否定的感觉很不好受。 其实很多工作并没有想象中的高大上,不要害怕,计算机就业的方向是真的广,不要走窄了&…

朋友圈新功能:实现定时发圈,自动跟圈

1.多号同时发圈 可以选择多个号同时发圈,提高工作效率。 2.定时发布 可以一次性设置完很多天的朋友圈,选好发送时间就可以解放双手。 3.一键转发 点击转发,可直接跳转到编辑页面。无需复制粘贴。 4.自动转发(跟圈) …

机能学实验通过ZL-620C一体化信息化生物信号采集系统具体呈现

ZL-621大屏教学试教系统为了实施机能学实验的教学改革,大力减轻教师的实验教学负担,主要功能电子白板,同步教学、控制、过程仿真、虚拟现实、三维动画、管理、音视频广播、PPT教材等于一体,大屏教学试教系统并能同时实现屏幕监视和…

湖北文理学院2024年成人高等继续教育招生简章

湖北文理学院,作为一所历史悠久、底蕴深厚的学府,始终致力于为社会各界培养具备高素质、专业技能和创新精神的优秀人才。在成人高等继续教育领域,湖北文理学院更是凭借其卓越的教学质量和丰富的教育资源,吸引了众多有志于提升自身…

Cesium入门学习(一)

下载cesium源代码 安装依赖 npm install注册账户,申请一个token 没有这个token,会导致地图中只能看到一个宇宙,没有办法看到地球 cesium的官网:cesium官网 替换token 替换对应位置的token 启动 运行 npm run build npm r…

72. UE5 RPG 实现召唤技能数量的限制,并优化技能相关

在上一篇文章里,我们实现了召唤技能,并且能够无限的召唤。所以,这属于一个bug,我们不能无限制的去召唤,这会影响游戏的体验。所以,在这篇里面,我们实现一下对召唤物数量的限制,并优化…

华为---- RIP路由协议基本配置

08、RIP 8.1 RIP路由协议基本配置 8.1.1 原理概述 RIP(Routing Information Protocol,路由协议)作为最早的距离矢量IP路由协议,也是最先得到广泛使用的一种路由协议,采用了Bellman-Ford算法,其最大的特点就是配置简单。 RIP协议要求网络中…

C++240618

1> 思维导图 2> 完善对话框,点击登录对话框, 如果账号和密码匹配,则弹出信息对话框,给出**提示”登录成功“** ,提供一个 **OK按钮**,用户点击**OK后**,**关闭登录界面**, 跳转…

C语言——扫雷小游戏

扫雷小游戏: 游戏最终效果: 1.先写一下游戏开始的简单界面。 用一个函数来写一下 void menu() {printf(" ---------------------------- \n");printf("| 1.play |\n");printf("| 0.exit …

SSM图书借阅管理系统-计算机毕业设计源码06780

摘 要 大数据时代下,数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求,利用互联网服务于其他行业,促进生产,已经是成为一种势不可挡的趋势。在图书馆的要求下,开发一款整体式结构的图书借阅管理系统&a…

valgrind工具的交叉编译及使用

一 概述 valgrind是一款非常好用的工具,用于检测内存泄漏等,这里讲述如何将其交叉编译到arm开发板及如何使用 【C/C 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南 - 知乎 (zhihu.com) valgrind: fai…

Python武器库开发-武器库篇之文件上传漏洞扫描器(六十二)

Python武器库开发-武器库篇之文件上传漏洞扫描器(六十二) 文件上传漏洞简介以及危害 文件上传漏洞是指在网站或应用程序中,攻击者可以通过合法的文件上传功能,由于对用户上传的文件没有进行严格的验证和过滤,导致攻击…

机器学习_SVM支持向量机

引入:在面对线性可分时,即用一条直线就可以区分数据的时候,需要将直线放在距离数据点距离最大化的位置,这个过程需要寻找最大间隔,即为最优化问题。当数据点不能用一根直线区分——线性不可分,就需要用核函…

免费Syslog日志接收工具

如果您想知道您的网络中发生了什么,以便洞察潜在的威胁并在它们变成攻击之前阻止它们,那么您需要查看您的日志。Syslog日志是网络设备、操作系统和应用程序生成的一种重要日志数据,通过有效地收集和监视Syslog日志,企业可以及时发…

设计模式(七)创建者模式之建造者模式

这里写目录标题 概述需求需求类图BikeBuilderMobikeBuilderOfoBuilderDirectorClientClient优缺点使用场景 模式扩展ComputerClient创建者模式对比工厂方法模式VS建造者模式抽象工厂模式VS建造者模式 总结 概述 建造者模式又叫生成器模式,是一种对象构建模式。它可…

Vue3中的常见组件通信之插槽

Vue3中的常见组件通信之插槽 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs…