请选择 进入手机版 | 继续访问电脑版

记录一个MyBatis缓存与事务引起的性能bug

[复制链接]
苍野狼步 发表于 2021-1-2 19:42:23 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
问题发现

最近在做的项目中,有一个功能模块涉及比力大数据量的查询和导出,分别是IMSI数据和MAC数据。刚开始这部门功能使用了级联查询,查询字段、查询条件使用函数(如在查询条件为时间戳,举行格式化为年与日)等利用,但是随着数据量加大查询效率大幅度低沉;所以厥后对那部门的功能举行了一些优化,如取消毗连查询,取消函数的使用,转而在业务逻辑中对关联表字段和时间举行设置和格式化。
而且导出也使用了EasyExcel举行导出,效率已经很高了。
但是上周前端要求导出功能响应时间要在1分钟之内,于是颠末协商,我们决定对导出数据举行最大记录限制,在实验了反复之后最后我将最大记录数控制在60W。
但是昨天前端再次找到我,说IMSI没有问题,但是MAC的导出超出了响应时间。
排查过程

于是我在当地举行两个接口的响应时间测试,发现同样的数据量,MAC比IMSI的导出速度满了不止一点半点,但是实在MAC的查询逻辑比IMSI还要简朴,实在想不明白,于是我开始逐行举行响应时间测试。
一开始我以为是查询效率的问题,但是颠末直接执行SQL和在业务中打断点测试SQL查询时间,都很正常。
厥后我开始测试前面说的,在业务中对关联字段和时间设置的逻辑。果不其然,IMSI处置处罚部门,纵然是60W,甚至100W条,也能在几秒内处置处罚完成;而MAC部门,纵然只有10W也半天处置处罚不完。
于是我开始在循环中打印对象,打印每一行处置处罚之后的时间。显着看得出MAC的打印过程十分的慢。每个循环中有两行利用,一行是将毫秒值转为Date,一行是通过设备ID查询数据库获取设备名称。我在每一行背面都将当前时间举行打印。说实话也是死马当活马医,万一看出问题了呢?
大概像这样
  1.         //处置处罚查询逻辑略……        //执行查询        List list = macDataMapper.queryMacInfo(macSearch);        //设置属性        System.out.println("遍历开始");        list.forEach(macVO -> {            macVO.setAcquisitionTime(new Date(macVO.getReportTime()));            System.out.println("收罗时间设置乐成"+System.currentTimeMillis());            macVO.setDeviceName(imsiSourceDataMapper.getEquipmentNameById(macVO.getDeviceNo()));            System.out.println("设备名称设置乐成"+System.currentTimeMillis());            System.out.println(macVO);        });
复制代码
同时IMSI也举行同样的处置处罚,先查他个100条,看一下打印的时间,原理是那里有问题
没想到果然被我发现了问题!双方打印出来的日志是这样的,左边是IMSI,右边是MAC

可以看到,每次查询数据库获取设备名称大概需要50毫秒左右的时间,而IMSI每次刚开始查询时确实每次都会查询,但是背面再遇到重复的设备时就不再查询了,而是直接迅速获取到效果;而MAC那里则每一次都会执行一次查询!
所以,实在是MyBatis的缓存机制的问题!一边使用了缓存机制而别的一边没有!
知识增补

以下内容泉源于网络资料(这篇博客:MyBatis 一级缓存、二级缓存全详解(一)
MyBatis 中的缓存就是说 MyBatis 在执行一次SQL查询大概SQL更新之后,这条SQL语句并不会消失,而是被MyBatis 缓存起来,当再次执行相同SQL语句的时候,就会直接从缓存中举行提取,而不是再次执行SQL下令。
MyBatis中的缓存分为一级缓存和二级缓存,一级缓存又被称为 SqlSession 级别的缓存,二级缓存又被称为表级缓存。
一级缓存是 SqlSession级别 的缓存。在利用数据库时需要构造 sqlSession 对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。差别的 sqlSession 之间的缓存数据区域(HashMap)是相互不影响的。用一张图来体现一下一级缓存,此中每一个 SqlSession 的内部都会有一个一级缓存对象。
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。
办理方式

那么,为什么同样的项目内里,双方一个启用了缓存一个没启用呢!
因为,缓存是基于事务的呀!!!
所以,办理办法就是在MAC查询那里添加事务就好了呀!
@Transactional(rollbackFor = Exception.class)
至此,问题办理,双方查询一样嗖嗖快!
总结

这真是个大坑,一个注解办理的问题我排查了很久才排查出来……不外也顺便详细相识了一下MyBatis的事务和缓存机制,是个不错的履历!以及,要公道使用事务呀!MAC那里是之前同事做的我接办的,我也妹想到他没用事务!挖坑!

来源:https://blog.csdn.net/u010827544/article/details/111696077
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )