首页
学习
活动
专区
工具
TVP
发布

使用Mybatis导致的OutOfMemoryError错误

使用Mybatis导致的OutOfMemoryError错误

我们系统中是用Mybatis开发,这个系统在生产环境运行了好几个月的时间了,没有出现过很严重的问题,突然有一天集群中的有2台报警无法提供服务,运维重启服务后正常。因为是生产上的问题,我们需要定位根本原因,查了那两台机器的日志,发现有OutOfMemoryError错误,错误信息如下

OutOfMemoryError

错误最终发生map的put上面,这个map是在UnknownTypeHandler的resolveTypeHandler方法中调用的。这个是现象,不是导致OutOfMemoryError的根本原因,但是这个方法确实会额外占用一些内存。(根本原因是数据量突然增多,一次查出了上百万的数据)

数据量大了这个方法也是挺占用内存的,下面就先对这个方法分析:

这个方法首先获取ResultSet的MataData,也就是每列的元数据,把这些信息组装成一个map,通过传入的列和这个map,确认当前列的位置。最后通过MataData和列的位置推断出当前列的TypeHandler。如果查出的列很多,数据量很大的情况下这个临时的map就有可能是压死骆驼的最后一根稻草。

resolveTypeHandler

Mybatis的TypeHandler

说到UnknownTypeHandler,就先看看TypeHandler,mybaits在查询出来的resultSet的每一列都会通过TypeHandler转成Java需要的类型,这个就是类型转换。Mybatis内置了很多的TypeHandler,如果框架提供的不能满足需求,我们也可以自定义一个TypeHandler。如果部署下TypeHandler,请参考下文:

Mybatis之TypeHandler简析

为什么会用UnknownTypeHandler呢?

如果代码走到了UnknownTypeHandler中,说明在程序启动解析resultmap的时候没有找到具体的TypeHanlder,只能借助运行期间推断出具体的TypeHanlder,这样程序就会多执行很多代码,影响了效率,也可能导致OOM的发生。

UnknownTypeHandler的注册

初始化的时候,会在TypeHandlerRegistry中注册所有的TypeHandler也包括UnknownTypeHandler,注册了三种情况下使用UnknownTypeHandler。

1、column的JavaType是Object

2、column的JavaType是Object,JdbcType是OTHRE

3、column的JdbcType是OTHRE

UnknownTypeHandler

除了以上,如果我们resultMap的type为java.util.Map,并且JavaType和typeHandler都没有定义,此时框架推断不出来具体的typeHandler,最终也会设置为UnknownTypeHandler。

如果resultMap的type为实体类,并且JavaType和typeHandler都没有定义,如果设置了当前类的property属性,框架推断到property指定变量的set方法的类型。

下面是我测试用的一个resultmap,所有列的类型都会用UnknownTypeHandler解析。

resultmap

说了这么多,总结一点:写代码的时候能明确就明确,少让框架自动去推断,推断是有成本的代价的。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200517A0GAL500?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券