1.mybatisԴ?码分????
2.MyBatis 原理:扫描 Mapper 接口
mybatisԴ?????
线上服务频繁遭遇 OutOfMemoryError(OOM)问题,对业务造成了严重影响,码分一天内服务重启多达五次,码分导致整个系统几乎瘫痪。码分通过Skywalking追踪,码分发现链路调用大部分呈现红色,码分模块源码查询亟待解决。码分作为排查者,码分我接手了这个任务。码分
首先,码分我分析了OOM的码分常见原因,主要包括堆内存和元空间不足。码分在我们的码分案例中,Mybatis的码分问题浮出水面。源码分析显示,码分Mybatis在拼接SQL时,通过集合存储SQL和参数,当SQL参数过多导致SQL过长时,集合会变得庞大,onetap源码回收不及时就会引发内存溢出。
由于环境限制,无法直接通过jstack、jmap工具定位问题,这增加了排查的难度。但在网络搜索中,我找到了一篇与DruidDataSource和Mybatis相关的问题,这让我找到了问题的线索,即多线程并发操作可能导致内存占用过高,httprunnermanager源码从而触发OOM。
进一步的源码分析揭示,DynamicContext类中的ContextMap(继承自HashMap)在存储SQL参数和占位符时,存在无法被GC回收的问题。当并发查询量增加时,这可能导致内存溢出。我通过线上复现情景,验证了这一理论,发现服务频繁进行Full GC,pythonminmaxloc源码最终引发了OOM。
针对问题,我提出解决方案:优化SQL拼接,避免过长的SQL体积,强调代码和SQL编写的重要性。同时,为了应对未来可能的故障,我配置了docker中的OOM保留dump文件,以备不时之需。emmc源码
MyBatis 原理:扫描 Mapper 接口
在MyBatis中,Mapper接口的扫描依赖MyBatis和Spring项目。实现Mapper接口的自动扫描主要有两种方式:@Mapper和@MapperScan注解。
@Mapper注解通常用于Mapper接口上,若仅需扫描带有该注解的接口,需引入mybatis/spring-boot-starter项目。在Spring未找到MapperScannerConfigurer和MapperFactoryBean的Bean时,AutoConfiguredMapperScannerRegistrar会自动扫描并注入Mapper接口的实现类。这个过程可通过MybatisAutoConfiguration的源码来理解。
相比之下,@MapperScan注解是Mybatis的常见扫描方式。它通过@Import(MapperScannerRegistrar.class)导入MapperScannerRegistrar,进行Mapper扫描逻辑。MapperScannerRegistrar通过实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法完成Mapper的扫描。
核心组件MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,其主要在registerBeanDefinitions方法中处理Mapper的自动注入。具体来说,它会创建ClassPathMapperScanner,扫描指定包中的Mapper,生成BeanDefinition,这些BeanDefinition最终会在Spring的Bean创建过程中被转换为Mapper的实例。
MapperFactoryBean是MyBatis/Spring用来表示Mapper的Bean,它基于SqlSessionDaoSupport,提供了FactoryBean接口的实现。获取Mapper时,会通过FactoryBean的getObject方法返回Mapper的代理类,如SqlSessionTemplate,它与Spring事务紧密关联并支持线程安全。
Configuration和MapperRegistry是MyBatis的核心配置,前者管理Mapper的信息,后者存储Mapper实例。在使用MapperRegistry获取Mapper时,会优先尝试从缓存中获取,只有当缓存中不存在时,才会创建新的MapperProxy实例。