MyBatis 源码分析之 Select 语句执行(下)
创始人
2024-02-06 22:04:09
0
  • 三哥

内容来自【自学星球】

欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。

想要了解更多,欢迎访问👉:自学星球

--------------SSM系列源码文章及视频导航--------------

创作不易,望三连支持!

SSM源码解析视频

👉点我

Spring

  1. Spring 中注入 Bean 的各种骚操作做
  2. Spring 中Bean的生命周期及后置处理器使用
  3. Spring 中容器启动分析之refresh方法执行之前
  4. Spring refresh 方法分析之一
  5. Spring refresh 方法之二 invokeBeanFactoryPostProcessors 方法解析
  6. Spring refresh 方法分析之三
  7. Spring refresh 方法之四 finishBeanFactoryInitialization 分析
  8. Spring AOP源码分析一
  9. Spring AOP源码分析二
  10. Spring 事务源码分析

SpringMVC

  1. SpringMVC 启动流程源码分析
  2. SpringMVC 请求流程源码分析

MyBatis

  1. MyBatis 源码分析之 SqlSessionFactory 创建
  2. MyBatis 源码分析之 SqlSession 创建
  3. MyBatis 源码分析之 Mapper 接口代理对象生成及方法执行
  4. MyBatis 源码分析之 Select 语句执行(上)
  5. MyBatis 源码分析之 Select 语句执行(下)
  6. MyBatis 源码分析一二级缓存

---------------------【End】--------------------

一、结果集 ResultSet 自动映射成实体类对象

回到下面代码:

return resultSetHandler. handleResultSets(ps);

//进行resultSet自动映射
return resultSetHandler. handleResultSets(ps);

在分析代码之前,我们先来看看 ResultSetHandler 和 ResultSetWrapper 两个类。

  • ResultSetHandler对查询结果进行处理
  • ResultSetWrapper 对ResultSet进行包装,可以方便地从ResultSet中访问特定的列
public interface ResultSetHandler {// 这里对结果集进行处理,返回的是集合 List handleResultSets(Statement stmt) throws SQLException;// 这里对结果集进行处理,返回的是游标 Cursor handleCursorResultSets(Statement stmt) throws SQLException;// 对存储过程的输出参数进行处理void handleOutputParameters(CallableStatement cs) throws SQLException;
}
public class ResultSetWrapper {// jdbc返回的结果集private final ResultSet resultSet;// 类型转换器注册中心private final TypeHandlerRegistry typeHandlerRegistry;// 查询结果中每列的名称private final List columnNames = new ArrayList<>();// 查询结果中每列的java类型private final List classNames = new ArrayList<>();// 查询结果中每列的jdbc类型private final List jdbcTypes = new ArrayList<>();// 每列对应的typeHandlerprivate final Map, TypeHandler>> typeHandlerMap = new HashMap<>();// 记录了总的映射列名,key是ResultMap的id,value是该ResultMap的列名集合private final Map> mappedColumnNamesMap = new HashMap<>();// 和上面的属性相反,记录了未映射的列名,key是ResultMap的id,value是该ResultMap未映射的列名集合private final Map> unMappedColumnNamesMap = new HashMap<>();public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {super();this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();this.resultSet = rs;final ResultSetMetaData metaData = rs.getMetaData();final int columnCount = metaData.getColumnCount();for (int i = 1; i <= columnCount; i++) {// columnLable代表原始的列名,columnName代表别名columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));classNames.add(metaData.getColumnClassName(i));}}
}

接着我们来看映射结果集方法源码:

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets

public List handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling results").object(mappedStatement.getId());final List multipleResults = new ArrayList();int resultSetCount = 0;// 获取第一个ResultSet,通常只会有一个ResultSetWrapper rsw = getFirstResultSet(stmt);// 从配置中读取对应的ResultMap,通常也只会有一个,设置多个是通过逗号来分隔,我们平时有这样设置吗?List resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);// 遍历多个查询结果集,一般只有一个,除非调用的是存储过程while (rsw != null && resultMapCount > resultSetCount) {// 获取当前结果集对应的ResultMapResultMap resultMap = resultMaps.get(resultSetCount);// 处理结果集handleResultSet(rsw, resultMap, multipleResults, null);// 获取结果集的下一个结果rsw = getNextResultSet(stmt);// 清空嵌套resultMapcleanUpAfterHandlingResultSet();resultSetCount++;}// resultSets是针对多结果集的情况下,给每个结果集一个名称,多个名称之间使用,分割String[] resultSets = mappedStatement.getResultSets();if (resultSets != null) {// 和resultMaps的遍历处理类似while (rsw != null && resultSetCount < resultSets.length) {ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);if (parentMapping != null) {String nestedResultMapId = parentMapping.getNestedResultMapId();ResultMap resultMap = configuration.getResultMap(nestedResultMapId);handleResultSet(rsw, resultMap, null, parentMapping);}rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}}return collapseSingleResultList(multipleResults);
}
 

多结果集只会在调用存储的时候出现,所以这里只介绍下单个结果集的情况,即 handleResultSet(rsw, resultMap, multipleResults, null) 方法。

1.1 结果集处理

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List multipleResults, ResultMapping parentMapping) throws SQLException {try {if (parentMapping != null) {// 这里处理多结果集的嵌套映射,不分析handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);} else {if (resultHandler == null) {// 如果用户没有指定对结果的处理器ResultHandler,那么默认会使用DefaultResultHandlerDefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);// 对结果集进行转换handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);// 将解析后的结果添加到multiResults中// 如果没有指定ResultHandler,那么默认会将解析之后的结果添加到multipleResults中multipleResults.add(defaultResultHandler.getResultList());} else {// 用户定义了对结果集的处理方法,即ResultHandler// 那么使用ResultSetHandler处理之后,会将结果再交给ResultHandler进行处理handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);}}} finally {// issue #228 (close resultsets)closeResultSet(rsw.getResultSet());}
}
 

该方法通过 handleRowValues 方法来映射 ResultSet 结果,并将并将映射的结果从 defaultResultHandler 的 ResultList 方法中取出存入 multipleResults 中,完成映射。

下面我们来看核心方法 handleRowValues 。

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValues

public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {// 判断是否有嵌套的映射if (resultMap.hasNestedResultMaps()) {ensureNoRowBounds();checkResultHandler();// 处理嵌套映射handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);} else {// 处理简单映射handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);}
}

我们可以通过 resultMap.hasNestedResultMaps() 知道查询语句是否是嵌套查询,如果 resultMap 中包含 和 且其 select 属性不为空,则为嵌套查询。

这里我们之分析简单查询。

1.2 简单查询映射

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {// ResultContext用来存放结果对象DefaultResultContext resultContext = new DefaultResultContext();// 根据 RowBounds 定位到指定行记录(取出rowbounds中的offset,跳过结果集中的前面offset行)skipRows(rsw.getResultSet(), rowBounds);// ResultSet是一个集合,很有可能我们查询的就是一个List,这就就每条数据遍历处理while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);// 从 resultSet 中获取结果Object rowValue = getRowValue(rsw, discriminatedResultMap);// 存储结果到resultHandler的ResultList,最后ResultList加入multipleResults中返回storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());}
}
 

该方法通过遍历结果集挨个调用 getRowValue 方法来进行结果集的映射,这里遍历映射是因为结果集可能不止一个。

RowBounds 是默认的分页工具(内存分页)。

下面我们来看看 getRowValue 方法的具体映射源码。

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap)

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {// 这个Map是用来存储延迟加载的BountSql的,我们下面来看final ResultLoaderMap lazyLoader = new ResultLoaderMap();// 创建实体类对象,比如 User 对象Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);// 判断结果值是否为空,并且没有对应当前结果java类型的typehandlerif (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final MetaObject metaObject = configuration.newMetaObject(rowValue);boolean foundValues = this.useConstructorMappings;if (shouldApplyAutomaticMappings(resultMap, false)) {//自动映射,结果集中有的column,但resultMap中并没有配置  foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;}// 根据  节点中配置的映射关系进行映射foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}return rowValue;
}

该方法的主要逻辑分为如下几个步骤:

  1. 创建实体类对象。
  2. 自动映射结果集中有的 column,但 resultMap 中并没有配置。
  3. 根据 节点中配置的映射关系进行映射。

1.2.1 创建实体

下面我们来看看结果集映射对象的创建。

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap)

Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createResultObject(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, org.apache.ibatis.executor.loader.ResultLoaderMap, java.lang.String)

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {// 用来判断是否使用到了构造方法参数映射this.useConstructorMappings = false; // reset previous mapping resultfinal List> constructorArgTypes = new ArrayList>();final List constructorArgs = new ArrayList();// 调用重载方法创建实体类对象Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);// 当前结果不为空,并且不存在可以直接将ResultSet转换为指定java类型的typeHandlerif (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final List propertyMappings = resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {// issue gcode #109 && issue #149// 如果开启了延迟加载,则为 resultObject 生成代理类,如果仅仅是配置的关联查询,没有开启延迟加载,是不会创建代理类if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {/** 创建代理类,默认使用 Javassist 框架生成代理类。* 由于实体类通常不会实现接口,所以不能使用 JDK 动态代理 API 为实体类生成代理。* 并且将lazyLoader传进去了*/resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);break;}}}// 如果结果对象不为空,并且构造方法使用到了构造参数映射,那么将useConstructorMappings设置为truethis.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping resultreturn resultObject;
}
 

下面重载方法 createResultObject 的实现逻辑

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createResultObject(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.util.List>, java.util.List, java.lang.String)

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List> constructorArgTypes, List constructorArgs, String columnPrefix)throws SQLException {final Class resultType = resultMap.getType();final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);// 取出构造函数参数的映射,就是FLAG为CONSTRUCTOR的映射final List constructorMappings = resultMap.getConstructorResultMappings();if (hasTypeHandlerForResultObject(rsw, resultType)) {// 如果符合当前java结果类型的TypeHandler,那么会使用typehandler来对结果集进行处理return createPrimitiveResultObject(rsw, resultMap, columnPrefix);} else if (!constructorMappings.isEmpty()) {// 如果指定了构造参数映射,使用构造参数映射来进行构造return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {// 如果是结果或者有默认构造函数,那么直接通过ObjectFactory来创建return objectFactory.create(resultType);} else if (shouldApplyAutomaticMappings(resultMap, false)) {// 判断是否开启了自动映射return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);}throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
 

通常我们的映射实体都是通过默认构造函数来进行创建的,也即 objectFactory.create(resultType) 方法逻辑。

objectFactory.create 的创建逻辑就是通过反射进行创建,就不看源码了。

1.2.2 自动映射

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap)

foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyAutomaticMappings

private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {// 获取查询结果集中出现但是没有定义resultMapping的列// ResultSetWrapper会通过ResultSet来解析出当前查询结果返回的所有列// 从ResultMap中可以获取到当前已经指定了映射的列// 然后就可以得出有哪些查询结果中的列没有指定映射List autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);boolean foundValues = false;if (!autoMapping.isEmpty()) {// 遍历这些没有指定映射的结果集中的列for (UnMappedColumnAutoMapping mapping : autoMapping) {// 使用typeHandler进行转换,转换成Java类型final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {// 通过MetaObject将值设置到结果对象中// gcode issue #377, call setter on nulls (value is not 'found')metaObject.setValue(mapping.property, value);}}}return foundValues;
}

该方法比较简单,先获取未配置 resultMap 映射节点的信息,即 List 对象,然后遍历该集合,获取属性值并设置到对象属性中,完成映射。

那我们来看看如何获取没有定义 resultMap 映射信息的集合,即 createAutomaticMappings 方法。

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createAutomaticMappings

private List createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {final String mapKey = resultMap.getId() + ":" + columnPrefix;// 从缓存中获取 UnMappedColumnAutoMapping 列表List autoMapping = autoMappingsCache.get(mapKey);// 缓存未命中if (autoMapping == null) {autoMapping = new ArrayList();// 从 ResultSetWrapper 中获取未配置在  中的列名final List unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);for (String columnName : unmappedColumnNames) {String propertyName = columnName;if (columnPrefix != null && !columnPrefix.isEmpty()) {// When columnPrefix is specified,// ignore columns without the prefix.if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {propertyName = columnName.substring(columnPrefix.length());} else {continue;}}// 将下划线形式的列名转成驼峰式,比如 AUTHOR_NAME -> authorNamefinal String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());if (property != null && metaObject.hasSetter(property)) {// 检测当前属性是否存在于 resultMap 中if (resultMap.getMappedProperties().contains(property)) {continue;}// 获取属性对于的类型final Class propertyType = metaObject.getSetterType(property);if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {final TypeHandler typeHandler = rsw.getTypeHandler(propertyType, columnName);// 封装上面获取到的信息到 UnMappedColumnAutoMapping 对象中autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));} else {configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, property, propertyType);}} else {configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);}}// 写入缓存autoMappingsCache.put(mapKey, autoMapping);}return autoMapping;
}

原来该方法是从 ResultSetWrapper 中获取未配置 中的列名啊!然后处理属性的命名即类型,最后封装成 UnMappedColumnAutoMapping 对象。

那我们来看看 getUnmappedColumnNames 方法源码。

org.apache.ibatis.executor.resultset.ResultSetWrapper#getUnmappedColumnNames

public List getUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {List unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));if (unMappedColumnNames == null) {// 加载已映射与未映射列名loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);// 获取未映射列名unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));}return unMappedColumnNames;
}

org.apache.ibatis.executor.resultset.ResultSetWrapper#loadMappedAndUnmappedColumnNames

private void loadMappedAndUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {List mappedColumnNames = new ArrayList();List unmappedColumnNames = new ArrayList();final String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH);// 获取  中配置的所有列名final Set mappedColumns = prependPrefixes(resultMap.getMappedColumns(), upperColumnPrefix);/** 遍历 columnNames,columnNames 是 ResultSetWrapper 的成员变量,保存了当前结果集中的所有列名* 这里是通过ResultSet中的所有列名来获取没有在resultMap中配置的列名* 意思是后面进行自动赋值时,只赋值查出来的列名*/for (String columnName : columnNames) {final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);// 检测已映射列名集合中是否包含当前列名if (mappedColumns.contains(upperColumnName)) {mappedColumnNames.add(upperColumnName);} else {// 将列名存入 unmappedColumnNames 中unmappedColumnNames.add(columnName);}}// 缓存列名集合mappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames);unMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);
}

获取未配置 resultMap 的映射流程很简单,就是先获取 resultMap 配置的映射信息,然后循环需要映射结果集对象的所有属性,如果属性在 resultMap 中则表示配置了映射信息放入 mappedColumnNamesMap 中,反正放入 unMappedColumnNamesMap ,最后将 unMappedColumnNamesMap 返回就是我们要的未配置 resultMap 映射信息的集合了。

1.2.3 resultMap 映射

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap)

foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyPropertyMappings

private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {// 获取已映射的列名final List mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);boolean foundValues = false;// 获取 ResultMapping集合final List propertyMappings = resultMap.getPropertyResultMappings();// 所有的ResultMapping遍历进行映射for (ResultMapping propertyMapping : propertyMappings) {String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);if (propertyMapping.getNestedResultMapId() != null) {// the user added a column attribute to a nested result map, ignore itcolumn = null;}if (propertyMapping.isCompositeResult()|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))|| propertyMapping.getResultSet() != null) {// 从结果集中获取指定列的数据Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);// issue #541 make property optionalfinal String property = propertyMapping.getProperty();if (property == null) {continue;// 若获取到的值为 DEFERED,则延迟加载该值} else if (value == DEFERED) {foundValues = true;continue;}if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {// gcode issue #377, call setter on nulls (value is not 'found')// 将获取到的值设置到实体类对象中metaObject.setValue(property, value);}}}return foundValues;
}

该方法的处理就是遍历 resultMap 配置的映射信息,挨个获取其对应的值,该值可能是关联查询结果也可能是普通结果,最后将获取到的值设置到映射结果对象中。

那接下来看看,这个 value 是如何获取的,方法源码。

org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getPropertyMappingValue

private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {if (propertyMapping.getNestedQueryId() != null) {// 获取关联查询结果return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);} else if (propertyMapping.getResultSet() != null) {addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?return DEFERED;} else {final TypeHandler typeHandler = propertyMapping.getTypeHandler();final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);// 从 ResultSet 中获取指定列的值return typeHandler.getResult(rs, column);}
}

这里和自动映射有一点不同,自动映射是从直接从ResultSet 中获取指定列的值,但是通过 ResultMap 多了一种情况,那就是关联查询,也可以说是延迟查询,此关联查询如果没有配置延迟加载,那么就要获取关联查询的值,如果配置了延迟加载,则返回DEFERED。

至此,我们的结果集映射就已经分析完成了。

好了,今天的内容到这里就结束了,我是 【J3】关注我,我们下期见


  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。

  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。

  • 感谢您的阅读,十分欢迎并感谢您的关注。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...