- 三哥
内容来自【自学星球】
欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。
想要了解更多,欢迎访问👉:自学星球
--------------SSM系列源码文章及视频导航--------------
创作不易,望三连支持!
SSM源码解析视频
👉点我
Spring
SpringMVC
MyBatis
---------------------【End】--------------------
回到下面代码:
return resultSetHandler. handleResultSets(ps);
//进行resultSet自动映射
return resultSetHandler.<E> handleResultSets(ps);
在分析代码之前,我们先来看看 ResultSetHandler 和 ResultSetWrapper 两个类。
public interface ResultSetHandler {
// 这里对结果集进行处理,返回的是集合
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
// 这里对结果集进行处理,返回的是游标
<E> Cursor<E> 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<String> columnNames = new ArrayList<>();
// 查询结果中每列的java类型
private final List<String> classNames = new ArrayList<>();
// 查询结果中每列的jdbc类型
private final List<JdbcType> jdbcTypes = new ArrayList<>();
// 每列对应的typeHandler
private final Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<>();
// 记录了总的映射列名,key是ResultMap的id,value是该ResultMap的列名集合
private final Map<String, List<String>> mappedColumnNamesMap = new HashMap<>();
// 和上面的属性相反,记录了未映射的列名,key是ResultMap的id,value是该ResultMap未映射的列名集合
private final Map<String, List<String>> 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<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<Object>();
int resultSetCount = 0;
// 获取第一个ResultSet,通常只会有一个
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 从配置中读取对应的ResultMap,通常也只会有一个,设置多个是通过逗号来分隔,我们平时有这样设置吗?
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
// 遍历多个查询结果集,一般只有一个,除非调用的是存储过程
while (rsw != null && resultMapCount > resultSetCount) {
// 获取当前结果集对应的ResultMap
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理结果集
handleResultSet(rsw, resultMap, multipleResults, null);
// 获取结果集的下一个结果
rsw = getNextResultSet(stmt);
// 清空嵌套resultMap
cleanUpAfterHandlingResultSet();
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) 方法。
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet
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 {
if (resultHandler == null) {
// 如果用户没有指定对结果的处理器ResultHandler,那么默认会使用DefaultResultHandler
DefaultResultHandler 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 属性不为空,则为嵌套查询。
这里我们之分析简单查询。
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForSimpleResultMap
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
// ResultContext用来存放结果对象
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
// 根据 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类型的typehandler
if (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;
}
该方法的主要逻辑分为如下几个步骤:
下面我们来看看结果集映射对象的创建。
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 result
final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
final List<Object> constructorArgs = new ArrayList<Object>();
// 调用重载方法创建实体类对象
Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
// 当前结果不为空,并且不存在可以直接将ResultSet转换为指定java类型的typeHandler
if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final List<ResultMapping> 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设置为true
this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
return resultObject;
}
下面重载方法 createResultObject 的实现逻辑
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#createResultObject(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.util.List
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);
// 取出构造函数参数的映射,就是FLAG为CONSTRUCTOR的映射
final List<ResultMapping> 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 的创建逻辑就是通过反射进行创建,就不看源码了。
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<UnMappedColumnAutoMapping> 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<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 中获取未配置在 中的列名
final List<String> 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 -> 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 {
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<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;
}
org.apache.ibatis.executor.resultset.ResultSetWrapper#loadMappedAndUnmappedColumnNames
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);
// 获取 中配置的所有列名
final Set<String> 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 映射信息的集合了。
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<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
// 获取 ResultMapping集合
final List<ResultMapping> 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 it
column = 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 optional
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())) {
// 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】关注我,我们下期见
。
由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。
如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。
感谢您的阅读,十分欢迎并感谢您的关注。