【开发篇】七、mybatis的foreach遍历,SQL拼接导致内存溢出

在这里插入图片描述

1、背景

文章微服务升级,新增了一个传入文章id的List,判断有多少id是存在的接口,第二天高峰期内存溢出。

2、快照文件分析

在这里插入图片描述

打开直方图,发现线程对象占用排第一。打开支配树,按深堆排序,选占用最大的线程对象,找到处理器方法HandlerMethod,List objects --> with outgoing references查看其关联的对象

在这里插入图片描述

在description中方找到当前线程在执行哪个方法

在这里插入图片描述

再回到支配树,发现有个字符串对象,深堆非常大,里面是一句SQL,而字符串底层是用字符数组实现的,其下方的char有157w大小,且char的浅堆也很大,点击发现里面是frch_item,而它的产生是因为SQL在拼接过程中用了foreach去遍历了一个大集合:

在这里插入图片描述
在这里插入图片描述

3、本地环境复现

找到快照文件中的相关代码:

@RestController
@RequestMapping("/sqljoint")
public class DemoSqlJointController {

    /**
     * 服务对象
     */
    @Resource
    private TbArticleService articleService;

    /**
     * 判断批量id存在多少个
     * size:传入生成的id数量
     */
    @GetMapping
    public ResponseEntity countIfAbsent(int size) {
        //随机生成批量id,模拟传入一个id的List
        List<Integer> ids = new Random().ints(0, 1000000).
                limit(size).boxed().collect(Collectors.toList());

        return ResponseEntity.ok(this.articleService.countIfAbsent(ids));
    }

}

Mapper层用foreach做了一个遍历

<!--判断当前id在不在数据库中,在就记为1,不在就记为0-->
    <select id="countIfAbsent" resultType="java.lang.Long">
        select
        IFNULL(sum(1),0)
        from article where
        <if test="ids != null and ids.size() > 0">
            id in
            <foreach collection="ids" item="item"  open="(" close=")" separator=",">
                #{item}
            </foreach>
        </if>
    </select>

在本地启动Jmeter,调整size的值

在这里插入图片描述

Visual发现size大时,JVM堆内存溢出

4、结论

Mybatis在使用foreach进行sql拼接时,会在内存中创建对象,如果foreach处理的数组或者集合元素个数过多,会占用大量的内存空间。

5、解决方式

  • 限制id个数的最大值
  • 将id缓存到redis,先用内存查

相关推荐

  1. Mybatis 动态 SQL - foreach

    2024-03-29 17:52:02       55 阅读
  2. Spark 中 BroadCast 导致内存溢出(SparkFatalException)

    2024-03-29 17:52:02       62 阅读
  3. MyBatis `<foreach>` 标签

    2024-03-29 17:52:02       39 阅读
  4. C语言 空指针导致内存溢出

    2024-03-29 17:52:02       67 阅读
  5. 使用foreach和stream并修改List列表

    2024-03-29 17:52:02       27 阅读
  6. STL——算法

    2024-03-29 17:52:02       58 阅读
  7. MyBatis `<foreach>`

    2024-03-29 17:52:02       40 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-29 17:52:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-29 17:52:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-29 17:52:02       87 阅读
  4. Python语言-面向对象

    2024-03-29 17:52:02       96 阅读

热门阅读

  1. c#使用linq封装分页查询

    2024-03-29 17:52:02       40 阅读
  2. 如何为 Git 配置邮箱地址

    2024-03-29 17:52:02       41 阅读
  3. 力扣练习3.28

    2024-03-29 17:52:02       39 阅读
  4. C++设计模式--工厂模式

    2024-03-29 17:52:02       45 阅读
  5. 在MySQL中字符串和整数比较的行为

    2024-03-29 17:52:02       35 阅读
  6. SystemUI入门之CentralSurfaces解析

    2024-03-29 17:52:02       44 阅读
  7. 【复杂网络建模】——建模工具Matlab进阶

    2024-03-29 17:52:02       40 阅读
  8. 基于NBIOT的物联网工程实训系统设计与实现

    2024-03-29 17:52:02       36 阅读
  9. springbean生命周期

    2024-03-29 17:52:02       37 阅读
  10. Android Fence机制

    2024-03-29 17:52:02       41 阅读