MyBatis 可以将查询结果,即结果集 ResultSet 自动映射成实体类对象。这样使用者就无
需再手动操作结果集,并将数据填充到实体类对象中。这可大大降低开发的工作量,提高工
作效率。
结果集的处理工作由结果集处理器ResultSetHandler执行。ResultSetHandler是一个接口,它只有一个实现类 DefaultResultSetHandler。结果集的处理入口方法是handleResultSets,下面来看一下该方法的实现。
handleResultSets
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public List<Object> handleResultSets(Statement stmt) throws SQLException { final List<Object> multipleResults = new ArrayList<Object>(); int resultSetCount = 0; // 获取第一个结果集 ResultSetWrapper rsw = getFirstResultSet(stmt); List<ResultMap> resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); // 处理结果集 handleResultSet(rsw, resultMap, multipleResults, null); // 获取下一个结果集 rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } // 以下逻辑均与多结果集有关,就不分析了,代码省略 String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) {...} return collapseSingleResultList(multipleResults); }
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException { // 获取结果集 ResultSet rs = stmt.getResultSet(); while (rs == null) { /* * 移动 ResultSet 指针到下一个上,有些数据库驱动可能需要使用者 * 先调用 getMoreResults 方法,然后才能调用 getResultSet 方法 * 获取到第一个 ResultSet */ if (stmt.getMoreResults()) { rs = stmt.getResultSet(); } else { if (stmt.getUpdateCount() == -1) { break; } } } /* * 这里并不直接返回 ResultSet,而是将其封装到 ResultSetWrapper 中。 * ResultSetWrapper 中包含了 ResultSet 一些元信息,比如列名称、 * 每列对应的 JdbcType、以及每列对应的 Java 类名(class name,譬如 * java.lang.String)等。 */ return rs != null ? new ResultSetWrapper(rs, configuration) : null; }
|
该方法首先从 Statement 中获取第一个结果集,然后调用 handleResultSet 方法对
该结果集进行处理。一般情况下,如果我们不调用存储过程,不会涉及到多结果集的问题。
单结果集的处理逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { try { if (parentMapping != null) { // 多结果集相关逻辑,不分析了 handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else { /* * 检测 resultHandler 是否为空。ResultHandler 是一个接口,使用者可 * 实现该接口,这样我们可以通过 ResultHandler 自定义接收查询结果的 * 动作。比如我们可将结果存储到 List、Map 亦或是 Set,甚至丢弃, * 这完全取决于大家的实现逻辑。 */ if (resultHandler == null) { // 创建默认的结果处理器 DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); // 处理结果集的行数据 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); multipleResults.add(defaultResultHandler.getResultList()); } else { // 处理结果集的行数据 handleRowValues(rsw,resultMap,resultHandler,rowBounds,null); } } } finally { closeResultSet(rsw.getResultSet()); } }
|
出镜率最高的 handleRowValues 方法,该方法用于处理结果集中的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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); } }
|
handleRowValues 方法中针对两种映射方式进行了处理。一种是嵌套映射,另一种是简
单映射。本文所说的嵌套查询是指ResultMap中嵌套了一个ResultMap
handleRowValuesForSimpleResultMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>(); // 根据 RowBounds 定位到指定行记录 skipRows(rsw.getResultSet(), rowBounds); // 检测是否还有更多行的数据需要处理 while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { // 获取经过鉴别器处理后的 ResultMap ResultMap discriminatedResultMap = resolveDiscriminatedResultMap( rsw.getResultSet(), resultMap, null); // 从 resultSet 中获取结果 Object rowValue = getRowValue(rsw, discriminatedResultMap); // 存储结果 storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } }
private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException { // 检测 rs 的类型,不同的类型行数据定位方式是不同的 if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) { if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) { // 直接定位到 rowBounds.getOffset() 位置处 rs.absolute(rowBounds.getOffset()); } } else { for (int i = 0; i < rowBounds.getOffset(); i++) { /* * 通过多次调用 rs.next() 方法实现行数据定位。 * 当 Offset 数值很大时,这种效率很低下 */ rs.next(); } } }
|
上面方法的逻辑较多,这里简单总结一下。如下:
- 根据 RowBounds 定位到指定行记录
- 循环处理多行数据
- 使用鉴别器处理 ResultMap
- 映射 ResultSet,得到映射结果 rowValue
- 存储结果
MyBatis 默认提供了 RowBounds 用于分页,从上面的代码中可以看出,这并非是一个高
效的分页方式。除了使用 RowBounds,还可以使用一些第三方分页插件进行分页。
getRowValue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); // 创建实体类对象,比如 Article 对象 Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null); if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(rowValue); boolean foundValues = this.useConstructorMappings; // 检测是否应该自动映射结果集 if (shouldApplyAutomaticMappings(resultMap, false)) { // 进行自动映射 foundValues = applyAutomaticMappings( rsw, resultMap, metaObject, null) || foundValues; } // 根据 <resultMap> 节点中配置的映射关系进行映射 foundValues = applyPropertyMappings( rsw, resultMap, metaObject, lazyLoader, null) || foundValues; foundValues = lazyLoader.size() > 0 || foundValues; rowValue=foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null; } return rowValue; }
|
上面的方法中的重要逻辑已经注释出来了,这里再简单总结一下。如下:
- 创建实体类对象
- 检测结果集是否需要自动映射,若需要则进行自动映射
- 按中配置的映射关系进行映射
创建实体类对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| // -☆- DefaultResultSetHandler private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { this.useConstructorMappings = false; final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>(); final List<Object> constructorArgs = new ArrayList<Object>(); // 调用重载方法创建实体类对象 Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix); // 检测实体类是否有相应的类型处理器 if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings(); for (ResultMapping propertyMapping : propertyMappings) { // 如果开启了延迟加载,则为 resultObject 生成代理类 if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) { // 创建代理类,默认使用 Javassist 框架生成代理类。由于实体类通常 // 不会实现接口,所以不能使用 JDK 动态代理 API 为实体类生成代理。 resultObject = configuration.getProxyFactory() .createProxy(resultObject, lazyLoader, configuration, objectFactory,constructorArgTypes, constructorArgs); break; } } } this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); return resultObject; }
|
创建好实体类对后,还需要对中配置的映射信息进行检测。若发现
有关联查询,且关联查询结果的加载方式为延迟加载,此时需为实体类生成代理类。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| /** 作者类 */ public class Author { private Integer id; private String name; private Integer age; private Integer sex; }
/** 文章类 */ public class Article { private Integer id; private String title; // 一对一关系 private Author author; private String content; }
|
Article 对象中的数据由一条 SQL 从 article 表中查询。Article 类有一个 author 字
段,该字段的数据由另一条 SQL 从 author 表中查出。
我们在将 article 表的查询结果填充到Article类对象中时,并不希望MyBaits立即执行另一条 SQL 查询 author 字段对应的数据。而是期望在我们调用article.getAuthor()方法时,MyBaits 再执行另一条 SQL 从 author 表中查询出所需的数据��
若如此,我们需要改造 getAuthor 方法,以保证调用该方法时可让 MyBatis执行相关的 SQL。
createResultObject 重载方法的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException { final Class<?> resultType = resultMap.getType(); final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory); // 获取 <constructor> 节点对应的 ResultMapping final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
// 检测是否有与返回值类型相对应的 TypeHandler,若有则直接从 // 通过 TypeHandler 从结果集中ᨀ取数据,并生成返回值对象 if (hasTypeHandlerForResultObject(rsw, resultType)) { // 通过 TypeHandler 获取ᨀ取,并生成返回值对象 return createPrimitiveResultObject(rsw, resultMap, columnPrefix); } else if (!constructorMappings.isEmpty()) { // 通过 <constructor> 节点配置的映射信息从 ResultSet 中ᨀ取数据, // 然后将这些数据传给指定构造方法,即可创建实体类对象 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("……"); }
|
createResultObject 方法中包含了 4 种创建实体类对象的方式。一般情况下,若无特殊要
求,MyBatis 会通过 ObjectFactory 调用默认构造方法创建实体类对象。ObjectFactory 是一个接口,大家可以实现这个接口,以按照自己的逻辑控制对象的创建过程。至此,实体类对象创建好了,接下里要做的事情是将结果集中的数据映射到实体类对象中。
结果集映射
MyBatis 中,结果集自动映射有三种等级。这三种等级官方文档上有所说明,这里直
接引用一下。如下:
- NONE 禁用自动映射。仅设置手动映射属性
- PARTIAL 将自动映射结果除了那些有内部定义内嵌结果映射的(joins)
- FULL 自动映射所有
除了以上三种等级,我们还可以显示配置置resultMap节点的 autoMapping 属性,以启用
或者禁用指定 ResultMap 的自动映射设定。
自动映射相关的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) { // 检测 <resultMap> 是否配置了 autoMapping 属性 if (resultMap.getAutoMapping() != null) { // 返回 autoMapping 属性 return resultMap.getAutoMapping(); } else { if (isNested) { // 对于嵌套 resultMap,仅当全局的映射行为为 FULL 时,才进行自动映射 return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior(); } else { // 对于普通的 resultMap,只要全局的映射行为不为 NONE,即可进行自动映射 return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior(); } } }
|
shouldApplyAutomaticMappings 方法用于检测是否应为当前结果集应用自动映射。检测
结果取决于resultMap节点的 autoMapping 属性,以及全局自动映射行为。
MyBatis 是如何进行自动映射的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { // 获取 UnMappedColumnAutoMapping 列表 List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings( rsw, resultMap, metaObject, columnPrefix); boolean foundValues = false; if (!autoMapping.isEmpty()) { for (UnMappedColumnAutoMapping mapping : autoMapping) { // 通过 TypeHandler 从结果集中获取指定列的数据 final Object value = mapping.typeHandler .getResult(rsw.getResultSet(), mapping.column); if (value != null) { foundValues = true; } if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) { // 通过元信息对象设置 value 到实体类对象的指定字段上 metaObject.setValue(mapping.property, value); } } } return foundValues; }
|
首先是获取UnMappedColumnAutoMapping 集合,然后遍历该集合,并通过 TypeHandler 从结果集中获取数据,最后再将获取到的数据设置到实体类对象中。
UnMappedColumnAutoMapping用于记录未配置在resultMap节点中的映射关系。该类定义在 DefaultResultSetHandler 内部,它的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private static class UnMappedColumnAutoMapping { private final String column; private final String property; private final TypeHandler<?> typeHandler; private final boolean primitive; public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) { this.column = column; this.property = property; this.typeHandler = typeHandler; this.primitive = primitive; } }
|
获取 UnMappedColumnAutoMapping 集合的过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| // -☆- DefaultResultSetHandler private List<UnMappedColumnAutoMapping> createAutomaticMappings( ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { final String mapKey = resultMap.getId() + ":" + columnPrefix; // 从缓存中获取 UnMappedColumnAutoMapping 列表 List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey); // 缓存未命中 if (autoMapping == null) { autoMapping = new ArrayList<UnMappedColumnAutoMapping>(); // 从 ResultSetWrapper 中获取未配置在 <resultMap> 中的列名 final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix); for (String columnName : unmappedColumnNames) { String propertyName = columnName; if (columnPrefix != null && !columnPrefix.isEmpty()) { if (columnName.toUpperCase(Locale.ENGLISH) .startsWith(columnPrefix)) { // 获取不包含列名前缀的属性名 propertyName = columnName.substring(columnPrefix.length()); } else { continue; } } // 将下划线形式的列名转成驼峰式,比如 AUTHOR_NAME -> authorName final 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 { // 若 property 为空,或实体类中无 property 属性,此时无法完成 // 列名与实体类属性建立映射关系。针对这种情况,有三种处理方式, // 1. 什么都不做 // 2. 仅打印日志 // 3. 抛出异常 // 默认情况下,是什么都不做 configuration.getAutoMappingUnknownColumnBehavior() .doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null); } } // 写入缓存 autoMappingsCache.put(mapKey, autoMapping); } return autoMapping; }
|
- 从 ResultSetWrapper 中获取未配置在中的列名
- 遍历上一步获取到的列名列表
- 若列名包含列名前缀,则移除列名前缀,得到属性名
- 将下划线形式的列名转成驼峰式
- 获取属性类型
- 获取类型处理器
- 创建 UnMappedColumnAutoMapping 实例
第一个步骤的逻辑,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| // -☆- ResultSetWrapper public List<String> getUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException { List<String> unMappedColumnNames = unMappedColumnNamesMap.get( getMapKey(resultMap, columnPrefix)); if (unMappedColumnNames == null) { // 加载已映射与未映射列名 loadMappedAndUnmappedColumnNames(resultMap, columnPrefix); // 获取未映射列名 unMappedColumnNames = unMappedColumnNamesMap.get( getMapKey(resultMap, columnPrefix)); } return unMappedColumnNames; }
private void loadMappedAndUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException { List<String> mappedColumnNames = new ArrayList<String>(); List<String> unmappedColumnNames = new ArrayList<String>(); final String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH); // 为 <resultMap> 中的列名拼接前缀 final Set<String> mappedColumns = prependPrefixes( resultMap.getMappedColumns(), upperColumnPrefix); // 遍历 columnNames,columnNames 是 ResultSetWrapper 的成员变量, // 保存了当前结果集中的所有列名 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); }
|
- 首先是从当前数据集中获取列名集合
- 然后获取中配置的列名集合。
- 之后遍历数据集中的列名集合,并判断列名是否被配置在了节点中。
- 若配置了,则表明该列名已有映射关系,此时该列名存入 mappedColumnNames 中。
- 若未配置,则表明列名未与实体类的某个字段形成映射关系,此时该列名存入 unmappedColumnNames 中。
- 这样,列名的分拣工作就完成了。
如上图所示:
- 实体类 Author 的id和name字段与列名id和name被配置在了resultMap中,它们之间形成了映射关系。
- 列名age、sex和email未配置在中,因此未与Author中的字段形成映射,所以他们最终都被放入了unMappedColumnNames 集合中。
MyBatis 是如何将结果集中的数据填充到已映射的实体类字段中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| // -☆- DefaultResultSetHandler private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { // 获取已映射的列名 final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix); boolean foundValues = false; // 获取 ResultMapping final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings(); for (ResultMapping propertyMapping : propertyMappings) { // 拼接列名前缀,得到完整列名 String column = prependPrefix( propertyMapping.getColumn(), columnPrefix); if (propertyMapping.getNestedResultMapId() != null) { column = null; } /* * 下面的 if 分支由三个或条件组合而成,三个条件的含义如下: * 条件一:检测 column 是否为 {prop1=col1, prop2=col2} 形式,该 * 种形式的 column 一般用于关联查询 * 条件二:检测当前列名是否被包含在已映射的列名集合中, * 若包含则可进行数据集映射操作 * 条件三:多结果集相关,暂不分析 */ if (propertyMapping.isCompositeResult() || (column != null && mappedColumnNames.contains( column.toUpperCase(Locale.ENGLISH))) || propertyMapping.getResultSet() != null) { // 从结果集中获取指定列的数据 Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix); final 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())) { // 将获取到的值设置到实体类对象中 metaObject.setValue(property, value); } } } return foundValues; }
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); return DEFERED; } else { final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler(); // 拼接前缀 final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix); // 从 ResultSet 中获取指定列的值 return typeHandler.getResult(rs, column); } }
|