线上问题回溯
使用阿里的EasyExcel通过springboot将数据导入到数据库,由于数据量较大,程序拆分成分批导入,每批100条数据,第一批数据导入大概 5s,从第二批开始,导入耗时递增,每批比上批大概多耗时 1s,第二批 6s 第三批 7s 第四批 8s
…导入5000条数据,大概几十分钟才导好 ,这显然性能不行!!!
排查过程
1:凭借码农经验,这种耗时一般是程序和磁盘交互耗时,数据库的写入和查询一般是造成程序的瓶颈
2:使用arthas监控程序排查,确实是程序在做一些IO操作的时候,耗时会递增,考虑到是不是使用框架的原因,因为项目使用的是远古ORM框架Hibernate,DEBUG调试,使用Hibernate查询的时候,会先从自己的缓存区中查询,并且查出来的对象是代理对象,数据写入的时候也会维护这个缓存区,考虑到是不是每次导入和查询都会维护这个缓存区导致程序越来越慢,因为每一批数据写入和查询都会导致这个缓存区的数据越来越大
DEBUG进入源码查看:
StatefulPersistenceContext中定义了很多缓存实体MAP
可见 缓存key数据库ID,value是对应的实体对象,此时缓存size=451
导入几轮之后,再查看缓存大小,此时增长到2717
问题定位
每一批导入结束之后,这个缓存MAP的数据越来越多,导致每次导入的时候,这个缓存的体量越来越大,维护的成本越来越大,资源消耗原来越多,导致时间越来越慢
解决
问题到这基本就知道怎么解决了,每一批导入结束之后,把缓存情况即可,清空之后,每次导入的耗时均衡了
clear方法具体实现:
总结
Hibernate框架确实能让开发变得更简单,基本脱离了sql语句,直接使用get方法就可以实现查询,但是方便的同时也带来了很多性能相关的问题,我们不能自己控制SQL语句的编写,完全依赖框架底层的封装,导致一些问题不好排查,打算以后用MybatisPuls替换这个ORM框架!希望本文对您有所帮助。