您的位置:首页 > 数据库

Mybatis3源码分析(16)-Sql解析执行-结果集映射(ResultSetHandler)

2015-12-22 13:51 1231 查看
在PreparedStatementHandler中的query()方法中,是用ResultSetHandler来完成结果集的映射的。

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}

Mybatis中只提供了一个ResultSetHandler的实现,那就是DefaultResultSetHandler。下面来看看他的handleResultSets()方法

public List<Object> handleResultSets(Statement stmt) throws SQLException {
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 = resultMaps.get(resultSetCount);
//完成映射,将结果加到入multipleResults中
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}

String[] resultSets = mappedStatement.getResulSets();
if (resultSets != null) {
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);
}

在实际运行过程中,通常情况下一个Sql语句只返回一个结果集,对多个结果集的情况不做分析 。实际很少用到。

继续看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 {
//一般情况resultHandler都为空,见ResultHandler.NO_RESULT_HANDLER
if (resultHandler == null) {
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
//生成对象,并加到defaultResultHandler.resultList集合中
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
//将结果加入multipleResults中
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
//关闭结果集
closeResultSet(rsw.getResultSet()); // issue #228 (close resultsets)
}
}

private 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);
}
}

简单映射handleRowValuesForSimpleResultMap

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext resultContext = new DefaultResultContext();
skipRows(rsw.getResultSet(), rowBounds);
while (shouldProcessMoreRows(rsw.getResultSet(), resultContext, rowBounds)) {
//discriminator的处理,可以根据条件选择不同的映射
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
//真正从ResultSet中映射出一个对象
Object rowValue = getRowValue(rsw, discriminatedResultMap);
//加入resultHandler.resultList中
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
//没有内映射
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//实例化一个对象,类型为resultMap.getType(),最终调用了ObjectFactory.create()方法
Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
//设置对象属性
final MetaObject metaObject = configuration.newMetaObject(resultObject);
boolean foundValues = resultMap.getConstructorResultMappings().size() > 0;
if (shouldApplyAutomaticMappings(resultMap, !AutoMappingBehavior.NONE.equals(configuration.getAutoMappingBehavior()))) {
//自动映射,结果集中有的column,但resultMap中并没有配置
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
//映射result节点
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
resultObject = foundValues ? resultObject : null;
return resultObject;
}
return resultObject;
}
以上代码开始总结出简单映射(没有内映射)的逻辑

每条结果都会生成一个java对象
根据构造方法实例化对象
自动映射(结果集有但在resultMap里没有配置的字段),有两情况会发生自动映射
在resultMap上配置了autoMapping="true"属性
在mybatis-config.xml配置了autoMappingBehavior="PARTIAL|FULL",默认为PARTIAL。

在实际应用中,都会使用自动映射,减少配置的工作。自动映射在Mybatis中也是默认开启的。
最后再映射属性。

根据构造方法实例化对象

<pre name="code" class="java">private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLExceptio
4000
n {
//构造方法中的参数类型
final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
//构造方法中具体值
final List<Object> constructorArgs = new ArrayList<Object>();
//根据构造方法生成对象
final Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) { // issue gcode #109 && issue #149
return configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
}
}
}
return resultObject;
}

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
final Class<?> resultType = resultMap.getType();
//resultMap配置中的construnctor节点
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
if (typeHandlerRegistry.hasTypeHandler(resultType)) {
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
} else if (constructorMappings.size() > 0) {
//construnctor节点有配置
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
} else {
//construnctor节点没有配置,调用无参的构造方法
return objectFactory.create(resultType);
}
}

private Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings, List<Class<?>> constructorArgTypes,
List<Object> constructorArgs, String columnPrefix) throws SQLException {
boolean foundValues = false;
for (ResultMapping constructorMapping : constructorMappings) {
final Class<?> parameterType = constructorMapping.getJavaType();
final String column = constructorMapping.getColumn();
final Object value;
//取出参数类型和具体的值
if (constructorMapping.getNestedQueryId() != null) {
value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
} else if (constructorMapping.getNestedResultMapId() != null) {
final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
value = getRowValue(rsw, resultMap);
} else {
final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
}
constructorArgTypes.add(parameterType);
constructorArgs.add(value);
foundValues = value != null || foundValues;
}
//创建对象
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}


自动映射

private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
//获取结果集中在resultMap中没有配置的列名
//如果resultMap中只设置了resultType="java.util.HashMap"的话,全都会在这里完成映射
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
for (String columnName : unmappedColumnNames) {
//属性名就是列名
String propertyName = columnName;
if (columnPrefix != null && columnPrefix.length() > 0) {
// When columnPrefix is specified,
// ignore columns without the prefix.
if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
propertyName = columnName.substring(columnPrefix.length());
} else {
continue;
}
}
//是否有对应的属性
final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
//是否有对应的set方法
if (property != null && metaObject.hasSetter(property)) {
final Class<?> propertyType = metaObject.getSetterType(property);
if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
if (value != null || configuration.isCallSettersOnNulls()) { // issue #377, call setter on nulls
if (value != null || !propertyType.isPrimitive()) {
//直接设置
metaObject.setValue(property, value);
}
foundValues = true;
}
}
}
}
return foundValues;
}

映射result节点

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) {
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
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(); // issue #541 make property optional
if (value != NO_VALUE && property != null && (value != null || configuration.isCallSettersOnNulls())) { // issue #377, call setter on nulls
if (value != null || !metaObject.getSetterType(property).isPrimitive()) {
//设置属性
metaObject.setValue(property, value);
}
foundValues = true;
}
}
}
return foundValues;
}

private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
if (propertyMapping.getNestedQueryId() != null) {
//子查询,这里就是会产生N+1次查询的地方,每个记录都会再执行一个子查询。子查询的过程这里就不在讨论了。
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
} else if (propertyMapping.getResultSet() != null) {
addPendingChildRelation(rs, metaResultObject, propertyMapping);
return NO_VALUE;
} else if (propertyMapping.getNestedResultMapId() != null) {
// the user added a column attribute to a nested result map, ignore it
return NO_VALUE;
} else {
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
//直接从结果集里获取。
return typeHandler.getResult(rs, column);
}
}

复杂映射(内映射)handleRowValuesForNestedResultMap

处理这种映射的逻辑比较复杂。这里先举例说明:
配置如下resultMap
<resultMap type="com.ashan.mybatis.User" id="detailUserResultMap"><!-- 整个resultMap会被解析成一个ResultMap对应 -->
<constructor>
<idArg column="user_id" javaType="String"/><!-- idArg会被解析成一个resultMapping对象 -->
<arg column="user_name" javaType="String"/><!-- resultMapping对象 -->
</constructor>

<result property="svcnum" column="svc_num" /> <!-- resultMapping对象 -->

<association property="cust" javaType="com.ashan.mybatis.Cust"> <!-- resultMapping对象 这个resultMapping对象指向了另一个ResultMap-->
<id property="id" column="cust_id"/>
<result property="custname" column="cust_name"/>
<result property="certNo" column="cert_no"/>
</association>

<collection property="accts" ofType="com.ashan.mybatis.Acct">
<id property="id" column="acct_id" />
<result property="payName" column="pay_name"/>
<result property="bankNo" column="bank_no"/>
</collection>

</resultMap>
假设需要映射的结果集:



可以看出,这个结果集将最终会映射成两个对象User对象,两个User对象对应的Cust对应都是cust_01,id为user_01对应的accts为:acct_01,acct_02,acct_04;user_02对应的acct只有一个acct_03。

User对象映射过程

下面来看Mybatis是怎么生成这两个User对象的。

private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
final DefaultResultContext resultContext = new DefaultResultContext();
skipRows(rsw.getResultSet(), rowBounds);
Object rowValue = null;
while (shouldProcessMoreRows(rsw.getResultSet(), resultContext, rowBounds)) {

//开始处理一行新的结果集记录
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);

//为这行记录生成一个key,createRowKey方法会利用idResultMapping(即idArg,和id节点)和resultMap的id来生成key
//例子中第1、2、4条记录生成的key都是一样的,大概内容为detailUserResultMap:user_01
//第3条记录生成的key大概内容为detailUserResultMap:user_02
final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
//nestedResultObjects是一个HashMap对象,在映射过程中所有生成的映射对象(包括内映射对象),都会生成一个key并保存在这里。
//例子中生成映射对象有三类:User,Cust,Acct

Object partialObject = nestedResultObjects.get(rowKey);
//如果是处理第1、3条记录,这里的parialObject为null值
//如果是处理第2、4条记录,这里的parialObject不为null
//
if (mappedStatement.isResultOrdered()) { // issue #577 && #542
//先不讨论
if (partialObject == null && rowValue != null) {
nestedResultObjects.clear();
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
} else {
//这个方法把结果集的记录映射成java对象
//处理第一条记录时,rowValue是新生成的User对象(user_01)其中属性cust为cust_01,accts里只有一个acct_01
//处理第二条记录时,rowValue对象就是第一条记录生成里的User对象,不过这时accts里多了一条acct_02
//处理第三条记录时,rowValue为新生成的User对象(user_02),cust属性为cust_01,accts只有一个acct_03
//处理第四条记录时,rowValue对象就是第一条记录生成里的User对象,这时accts里又多了一条acct_04
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, rowKey, null, partialObject);
//只有第一条记录和第三条记录partialObject才会为null
if (partialObject == null) {
//把User对象加入到resultHandler.resultList中,这里也可以看出,虽然有四条记录,但只会被映射成两个User对象
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
}
if (rowValue != null && mappedStatement.isResultOrdered()) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}


接下来继续看User对象的生成过程
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey, String columnPrefix, Object partialObject) throws SQLException {
final String resultMapId = resultMap.getId();
Object resultObject = partialObject;
//第一和第三条记录时,partialObject为null, resultObject也为null
if (resultObject != null) {
//处理第二、四条记录里会执行这里
final MetaObject metaObject = configuration.newMetaObject(resultObject);
putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
//直接调用内映射,即设置处理cust和accts,例子中主要是加入一个acct,因为cust只有一个,在user对象创建里就会被创建
applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
ancestorObjects.remove(absoluteKey);
} else {
//处理第一、三条记录里会执行这里,说明需要创建一个新的User对象
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//创建一个user对象,跟简单映射的处理方式一样
resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(resultObject);
boolean foundValues = resultMap.getConstructorResultMappings().size() > 0;
if (shouldApplyAutomaticMappings(resultMap, AutoMappingBehavior.FULL.equals(configuration.getAutoMappingBehavior()))) {
//自动映射,跟简单映射的处理方式一样,跟简单映射的处理方式一样,例子中不会执行这一步
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
//映射reulst节点,跟简单映射的处理方式一样,跟简单映射的处理方式一样 ,例子中主要映射svc_num
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
//调用内映射,即生成cust和acct对象并设置到User对象中
foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
ancestorObjects.remove(absoluteKey);
foundValues = lazyLoader.size() > 0 || foundValues;
resultObject = foundValues ? resultObject : null;
}
//注意这里,生成User对象里combinedKey就是User对象的key,将新创建的两个User对象加入nestedResultObjects中,以便后续处理使用,在处理第二、四条记录里就可以使用对应的User对象了。
if (combinedKey != CacheKey.NULL_CACHE_KEY) nestedResultObjects.put(combinedKey, resultObject);
}
return resultObject;
}


上面是User对象的生成过程。nestedResultObjects在处理过程的作用很重要,由这个容器来控制是否需要创建新的User对象。

Cust对象映射过程

再来看Cust对象是怎么生成并加入到User对象中的
//处理内映射,生成内映射对象,并加入到上层对象中。这
c7f5
里主要根据例子分析Cust对象的生成,上层对象为User
private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
boolean foundValues = false;
for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
final String nestedResultMapId = resultMapping.getNestedResultMapId();
if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
//resultMap中的collection,association节点都会被生成一个nestedResultMap,这里分析Cust对象,也就是association
try {
final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
//获取内映射的ResultMap
final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
CacheKey rowKey = null;
Object ancestorObject = null;
if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
//第二、三、四记录时会执行,ancestorColumnPrefi也是一个HashMap,保存的是什么内容下面再看
//第一条记录时,肯定不会有这个对应关系
rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));

//这个ancestorObjects是一个HashMap跟名字一样只会保存原始对应,也就是上层对象,这里cust和acct对象是最下层的对象了。也就是说cust和acct没有内映射了
//所以例子中ancestorObjects只会保留User对象
ancestorObject = ancestorObjects.get(rowKey);
}
if (ancestorObject != null) {
if (newObject) metaObject.setValue(resultMapping.getProperty(), ancestorObject);
} else {
//映射四条记录的Cust对应都会执行这里
//这里是生成内映射Cust的key,大概是这样的:Cust:cust_01
rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);

//这里的combineKeys是跟上层对象组合成的一个key
//parentRowKey为上层对象(User对象)的key,第一、二、四条记录为user_01,第三条记录为user_02
//这样combineKey值大概为:第一、二、四条记录为user_01:cust_01,第三条记录为user_02:cust_01
final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);

//从nestedResultObjects获取
//第一、三条记录rowValue是为null的,第二、四条记录与第一条记录的combinedKey一样,所以rowValue的值不一样
Object rowValue = nestedResultObjects.get(combinedKey);
boolean knownValue = (rowValue != null);
//检查要映射的对象是否为Collection类型,这里是Cust类型,collectionProperty为null
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
//生成Cust对象
//注意入参的rowValue,第一、三条记录为null
rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
if (rowValue != null && !knownValue) {
//第一、三条记录时才会执行这里,第二、四条记录用的是第一条中的Cust对象,不用重复设置

if (collectionProperty != null) {
//User.cust属性不是集合,不会执行这里
final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
targetMetaObject.add(rowValue);
} else {
//将生成的Cust对象设置到User对象中
metaObject.setValue(resultMapping.getProperty(), rowValue);
}
foundValues = true;
}
}
}
} catch (SQLException e) {
throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
}
}
}
return foundValues;
}


再来看getRowValue是怎么处理Cust对象的,这个getRowValue上前讲Cust对象时的代码一样的,只不过这次是对Cust对象为分析
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, CacheKey absoluteKey, String columnPrefix, Object partialObject) throws SQLException {
//partialObject,第一、三条为null,第二、四条用是的第一条里的Cust,不为null
final String resultMapId = resultMap.getId();
Object resultObject = partialObject;
if (resultObject != null) {
//第二、四条记录
final MetaObject metaObject = configuration.newMetaObject(resultObject);
putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
//这个时间只需要处理Cust里的内映射就行了,例子中Cust没有内映射,这里将什么都不会发生
//相当对处理第二、四条记录时,这个方法什么都没做
applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
ancestorObjects.remove(absoluteKey);
} else {
//第一、三条记录
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//实例化
resultObject = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(resultObject);
boolean foundValues = resultMap.getConstructorResultMappings().size() > 0;
if (shouldApplyAutomaticMappings(resultMap, AutoMappingBehavior.FULL.equals(configuration.getAutoMappingBehavior()))) {
//自动映射
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
//映射result节点
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix);
//内映射,例子中Cust没有内映射
foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
ancestorObjects.remove(absoluteKey);
foundValues = lazyLoader.size() > 0 || foundValues;
resultObject = foundValues ? resultObject : null;
}
//将新创建的Cust对象加入nestedResultObjects中
if (combinedKey != CacheKey.NULL_CACHE_KEY) nestedResultObjects.put(combinedKey, resultObject);
}
return resultObject;
}
从上面的代码可以看出,虽然四条记录对应的cust_id都为cust_01,按一般的ORM映射来说,在内存中四个User对象的Cust属性应该是同一个,但在这里个例子中会生成两个Cust对象。这是因为nestedResltOjects是用CombineKey,至于为什么这样做,还不知道!

Acct对象映射过程

Acct对象映射过程,还是applyNestedResultMapping方法
private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
boolean foundValues = false;
for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
final String nestedResultMapId = resultMapping.getNestedResultMapId();
if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
try {
final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
CacheKey rowKey = null;
Object ancestorObject = null;
if (ancestorColumnPrefix.containsKey(nestedResultMapId)) {
rowKey = createRowKey(nestedResultMap, rsw, ancestorColumnPrefix.get(nestedResultMapId));
ancestorObject = ancestorObjects.get(rowKey);
}
if (ancestorObject != null) {
if (newObject) metaObject.setValue(resultMapping.getProperty(), ancestorObject);
} else {
//四条记录都会执行这里
//四条记录都生成不同的rowKey的,大概为acct_01,acct_02,acct_03,acct_04
rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);

//parentRowKey为User对象的key
//四条记录的combinedKey大概为user_01:acct_01,user_01:acct_02,user_02:acct_03,user_01:acct_04
final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
Object rowValue = nestedResultObjects.get(combinedKey);
boolean knownValue = (rowValue != null);

//实例化集合属性
//这里User.accts对象为一个集体,instantiateCollectionPropertyIfAppropriate方法会取出accts属性的值,如果为null则创建一个,并设置到User对象中
//第一、二、四条记录返回的都是同一个,因为他们对应同一个User对象
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) {
//生成Acct对象
rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, columnPrefix, rowValue);
if (rowValue != null && !knownValue) {
if (collectionProperty != null) {
final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
//加入到集合中
targetMetaObject.add(rowValue);
} else {
metaObject.setValue(resultMapping.getProperty(), rowValue);
}
foundValues = true;
}
}
}
} catch (SQLException e) {
throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
}
}
}
return foundValues;
}
private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
//属性名,这里为accts
final String propertyName = resultMapping.getProperty();
//设置值
Object propertyValue = metaObject.getValue(propertyName);
if (propertyValue == null) {
//如果为空,先看他的类型
Class<?> type = resultMapping.getJavaType();
if (type == null) {
type = metaObject.getSetterType(propertyName);
}
try {
if (objectFactory.isCollection(type)) {
//如果是集合类型

//生成一个集合对象
propertyValue = objectFactory.create(type);

//设置到User对象中,即User.setAccts(list)方法
metaObject.setValue(propertyName, propertyValue);
return propertyValue;
}
} catch (Exception e) {
throw new ExecutorException("Error instantiating collection property for result '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
}
} else if (objectFactory.isCollection(propertyValue.getClass())) {
return propertyValue;
}
return null;
}

小结

到此,Mybatis是怎么利用ResultSet生成对象的过程已经分析完毕。分为简单映射和复杂映射。
简单映射就是不包含内映射的resultMap
复杂映射就是包含内映射的resultMap。
复杂映射的过程比较复杂,源代码也没有一行注释,本人是写了个实例,再通过eclipse中的debuger一步步来分析的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java jdbc mybatis sql 源码