news 2026/5/4 22:52:18

同事写了一条 SQL,把 MyBatis 都干翻了。。

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
同事写了一条 SQL,把 MyBatis 都干翻了。。

前言

继上次线上CPU出现了报警,这次服务又开始整活了,风平浪静了没几天,看生产日志服务的运行的时候,频繁的出现OutOfMemoryError,就是我们俗称的OOM,这可还行!频繁的OOM直接会造成服务处于一个不可用的情况,通过Skywalking查看链路调用,基本全报红了,基本处于一个瘫痪状态,因为生产该服务是分布式部署,运维当即立断对该服务进行重启,因为是B端的产品,先让公司业务能用起来了,保证服务的正常使用,然后紧急查看问题,当然这个问题就来到了我这里,既然分配给我了,咱高低给它查出来,并且修复了。

OutOfMemoryError出现的原因

先来了解下OutOfMemoryError出现的原因,无非就是两类堆内存空间不足、元空间不足

  1. 堆内存空间不足:意味着程序存在一直有引用的对象(强引用),主要对象在引用的状态就无法被GC回收,撑爆了-Xmx堆拓展的最大值,内存不足自然就会触发堆内存溢出。

  2. 元空间:Java 8引入了元空间概念,代替了之前堆的永久代,由于元空间属于堆外内存,不需要有对象引用,通过指针的方式表示类和元数据,之所以引用元空间就是一种JDK的升级优化,避免了永久代的内存溢出。

常见堆内存溢出的几种情况

  1. 查询数据库返回的数据量过大,加载到内存中导致内存溢出;

  2. 代码中出现死循环情况,导致大对象一直被引用不能被GC回收;

  3. 资源链接池、io流在使用完没有进行手动释放;

  4. 静态集合类里面存在引用对象,始终存在引用关系,没有进行清除;

以上属于常见的几种堆内存溢出的场景,当然有时候我们的遇到的问题都是稀奇古怪的问题,常见的问题总是很少能遇到…

现象分析

根据生产环境的报错日志来看,这边属于Mybatis报出的一个内存溢出情况,通过去看Mybatis源码发现,底层也是通过一些集合类来存放拼接的sql,那么当然也有可能出现堆内存溢出,而且在sql体积比较大的情况下,接收sql的集合就会变的非常大,如果回收不了那么就会导致内存溢出。

由于我们docker容器里面没有一些jstack、jmap的工具,并且dump文件也没有进行保存…导致我无法通过看线程高占用内存的对象,来分析具体是什么操作发生的内存溢出,这就难了… 于是只能去网上搜搜看了,没想到真的给到我一些启发,并且有点思路大概知道是哪里的问题。

文章来源于zzzzbw作者写一篇关于 《惨遭DruidDataSource和Mybatis暗算,导致OOM》,很感谢🙏这位作者给我带来的启发。 文章作者也遇到了Mybatis带来的OOM,主要是因为Mybatis拼接SQL的时候生成的占位符和参数对象,存放在Map里,当SQL的参数多导致SQL太长的时候,Map持有这些SQL时间较长,并且多线程同时操作,这时候内存占用就很高,从而发生OOM

Mybatis源码分析

通过对DynamicContext类源码查看,DynamicContext又一个ContextMap 类型的参数bindings,继承了HashMap相当于一个Map集合,接着看这个类中的getBindings方法,看到了ForEachSqlNode这类调用了getBindings方法,简单的说就是ForEachSqlNode通过getBindings方法,将SQL参数和参数的占位符统一put到ContextMap这个集合里面,主要是这里面的参数和占位符无法被GC回收,并发查询量多的情况下就会导致OOM。

情景复现

随后我做了线上场景的复现,通过将SQL语句的拼接,将IN里面的参数变大,然后创建50个线程进行执行,将JVM堆内存设为-Xmx256m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

这里看控制台打印的日志,服务在频繁的进行Full GC,导致OOM。

总结

既然发现了问题出现的原因,接下来就是对代码SQL进行优化,尽量避免在sql拼接的时候体积过大,这里告诫我们代码不能乱写,SQL语句也不能随意写啊,有时候把问题想的过于简单确实会带来不可预知的风险。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 20:43:17

常见问题及参考链接

1、ubuntu 搜狗输入法安装 和 无法输入中文 https://blog.csdn.net/ytusdc/article/details/132378645 2、Ubuntu 20.04 中 Git 的安装、配置和基本操作指南 https://blog.csdn.net/m0_73359068/article/details/146930790 3、

作者头像 李华
网站建设 2026/5/4 20:45:27

搞定 Nginx 生产部署:避坑指南 + 最佳实践

先灵魂拷问一下:写了一堆接口却不会部署?服务器被恶意请求打崩过?静态资源加载慢到用户想摔手机?别慌!Nginx 作为后端工程师的「部署瑞士军刀」,能搞定反向代理、负载均衡、限流防刷等一堆骚操作。记住咯&a…

作者头像 李华
网站建设 2026/5/2 17:01:05

基于LangChain手工测试用例生成工具

在编写测试用例的过程中,测试工程师会通过需求文档,研发的概要设计等信息编写测试用例,测试用例的输出格式常常为思维导图或者excel等数据信息。 在以上的流程中,一个测试工程师可以根据比较详细的需求文档以及研发的概要设计输出…

作者头像 李华
网站建设 2026/5/1 6:10:29

接口性能优化的11个小技巧

接口性能优化 对于从事后端开发的同学来说,肯定再熟悉不过了,因为它是一个跟开发语言无关的公共问题。 该问题说简单也简单,说复杂也复杂。 有时候,只需加个索引就能解决问题。 有时候,需要做代码重构。 有时候&am…

作者头像 李华
网站建设 2026/5/4 12:04:39

git个人开发流程

1. 标准开发流程 (针对个人项目) 第一步:同步主分支 (保持起点最新) # 1. 切换回主分支 git checkout main# 2. 拉取远程最新代码 (防止你在这个设备开发时,在另一个设备Push过代码) git pull origin main 第二步:新建并切换分支 不要在 …

作者头像 李华
网站建设 2026/5/3 8:04:09

智能安防(有完整资料)

资料查找方式:特纳斯电子(电子校园网):搜索下面编号即可编号:CP-51-2021-051设计简介:本设计是基于单片机的智能安防系统,主要实现以下功能:可通过LCD1602安防状态和是否有人&#x…

作者头像 李华