这是我参与8月更文挑战的第30天,活动详情查看:8月更文挑战
嵌套查询与懒加载的代码实现这里不再赘述,见文章Mybatis之缓存、懒加载。下面我们来直接分析源码,看看懒加载的执行过程。
时序图
BaseExecutorSimpleExecutorPreparedStatementHandlerDefaultResultSetHandlerqueryqueryFromDatabasedoQueryqueryhandleResultSetshandleResultSethandleRowValueshandleRowValuesForSimpleResultMapgetRowValueapplyPropertyMappingsgetPropertyMappingValuegetPropertyMappingValueList
BaseExecutor#query
- query方法,所有查询都需要经过这里,如果是普通查询,则进入查询时queryStack=1,查询结束后queryStack=0
- 如果是嵌套查询,进入嵌套外部查询时,queryStack=1,进入嵌套内部查询时,queryStack=2,嵌套内部查询结束后queryStack=1,嵌套外部查询结束后queryStack=0.
1 | java复制代码/** |
DefaultResultSetHandler#getRowValue
- 在getRowValue方法中,会先创建接收结果的空对象
- 判断是否开启自动映射,开启自动映射的配置及枚举如下
1 | xml复制代码<setting name="autoMappingBehavior" value="PARTIAL"/> |
1 | java复制代码// 自动映射选项 |
- 根据resultMap标签配置的映射关系进行映射
1 | java复制代码/** |
DefaultResultSetHandler#createResultObject
- 在createResultObject方法中,会根据resultMap标签中的type属性来创建结果集的接收对象
- 如果当前属性是嵌套查询,并且是懒加载,则会创建接收对象的代理对象,代理类是EnhancedResultObjectProxyImpl
1 | java复制代码private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { |
DefaultResultSetHandler#applyPropertyMappings
- 获取
ResultSet
中的列名 - 获取
resultMap
标签中的映射配置 - 调用方法
getPropertyMappingValue
获取对应的结果值 - 拿到映射关系对应的属性名称
- 调用
metaObject.setValue
方法对属性进行赋值
1 | java复制代码private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix) |
DefaultResultSetHandler#getPropertyMappingValue
- 如果当前映射是嵌套查询,则调用
getNestedQueryMappingValue
方法获取对应列的值 - 如果是普通查询,则直接调用
TypeHandler
中的getResult
方法获取对应列的值
1 | java复制代码private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) |
DefaultResultSetHandler#getNestedQueryMappingValue
- 如果是非懒加载,则会根据加载好的参数,立即执行查询
BaseExecutor#query
,并将结果返回 - 如果是懒加载,则会以当前属性名的全大写作为key,将执行查询所需的各项条件封装值作为value,存入lazyLoader中
1 | java复制代码private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) |
到这里,如果是懒加载,则懒加载的属性值为空,查询结束;如果不是懒加载,嵌套内部查询在查询出结果后,对该属性赋值,整个嵌套查询就结束了。而如果是懒加载,返回的对象是一个代理对象,当调用对象中的方法时就会走到代理类的
intercept
方法中。
由于在XML中配置了CGLIB代理,因此这里走到了CglibProxyFactory
类中。这里可以配置使用CGLIB代理或者JDK代理。
1 | xml复制代码<!--指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。CGLIB | JAVASSIST--> |
CglibProxyFactory.EnhancedResultObjectProxyImpl#intercept
- 普通方法调用,进入到else代码块
- 对于激进加载属性
aggressive
,可以在XML中进行配置
1 | xml复制代码<!--当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载,默认值false--> |
- 当调用属性的get方法,并且lazyLoader中包含有该属性,则加载该属性的值
1 | java复制代码/** |
以上就是Mybatis懒加载的实现原理。
本文转载自: 掘金