记一次mybatis结果集映射源码

记一次mybatis结果集映射源码

背景

同事在使用resultMap时,内嵌了collections元素,并且collections里面还内嵌一层collections。模拟代码如下:

 <resultMap id="base" type="my.mybatis.entity.User">\\用户
   <id property="id" column="id"/>
   <collection property="roles" ofType="my.mybatis.entity.Role"  columnPrefix="role_">\\权限
     <id property="id" column="id"/>
     <collection property="menus" ofType="my.mybatis.entity.Menu" columnPrefix="menu_">\\菜单
       <id property="id" column="id"/>
     </collection>
   </collection>
 </resultMap>

 <sql id="Base_Column_List">
   	user.id,
   	role.id as role_id,
   	menu.id as menu_id
   </sql>

但是发现最内层的menus属性一直都为空,无法映射到entity里。在网上找了一下,发现没有什么答案,就决定看mybatis的源码,找一下对象映射的逻辑。

先讲无法映射的原因

由于第一层collection写明了columnPrefix=“role_”,第二层collection写明了columnPrefix=“menu_”。
第二层的前缀会继承第一层的字段映射前缀。
即 mybatis的结果集映射时 会找 role_menu_id的字段
所以正确的sql字段写法为

 <sql id="Base_Column_List">
   	user.id,
   	role.id as role_id,
   	menu.id as role_menu_id
   </sql>

源码逻辑

public class DefaultResultSetHandler implements ResultSetHandler {
....................
      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);
       }
     }

   	  private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, 
   	  				ResultHandler<?> resultHandler, RowBounds rowBounds, 
   	  				ResultMapping parentMapping) throws SQLException {
       final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
       skipRows(rsw.getResultSet(), rowBounds);
       Object rowValue = previousRowValue;
       while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
         final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
         final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
         Object partialObject = nestedResultObjects.get(rowKey);
         // issue #577 && #542
         if (mappedStatement.isResultOrdered()) {
           if (partialObject == null && rowValue != null) {
             nestedResultObjects.clear();
             storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
           }
           //结果集映射
           rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
         } else {
           rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
           if (partialObject == null) {
             storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
           }
         }
       }
       if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
         storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
         previousRowValue = null;
       } else if (rowValue != null) {
         previousRowValue = rowValue;
       }
     }
     //
     // GET VALUE FROM ROW FOR NESTED RESULT MAP
     //
   	private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, 
   			String columnPrefix, Object partialObject) throws SQLException {
       final String resultMapId = resultMap.getId();
       Object rowValue = partialObject;
       if (rowValue != null) {
         final MetaObject metaObject = configuration.newMetaObject(rowValue);
         putAncestor(rowValue, resultMapId, columnPrefix);
         applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
         ancestorObjects.remove(resultMapId);
       } else {
         final ResultLoaderMap lazyLoader = new ResultLoaderMap();
         //使用反射实例化entity
         rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
         if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
           final MetaObject metaObject = configuration.newMetaObject(rowValue);
           boolean foundValues = this.useConstructorMappings;
           if (shouldApplyAutomaticMappings(resultMap, true)) {
             foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
           }
           //映射普通字段
           foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
           putAncestor(rowValue, resultMapId, columnPrefix);
           //映射嵌套的结果集
           foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
           ancestorObjects.remove(resultMapId);
           foundValues = lazyLoader.size() > 0 || foundValues;
           rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
         }
         if (combinedKey != CacheKey.NULL_CACHE_KEY) {
           nestedResultObjects.put(combinedKey, rowValue);
         }
       }
       return rowValue;
     }
     
    /**
     * @param metaObject 上一层对象的封装类
     **/
   	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();
   	      //如果是嵌套的ResultMap,即collection元素
   	      if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
   	        try {
   	          //组成嵌套 prefix
   	          final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
   	          //取的嵌套的ResultMap,然后 重新走getObjectValue方法,对ResultMap的resultMapping赋值
   	          final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
   	          if (resultMapping.getColumnPrefix() == null) {
   	            // try to fill circular reference only when columnPrefix
   	            // is not specified for the nested result map (issue #215)
   	            //寻找第一层父对象
   	            Object ancestorObject = ancestorObjects.get(nestedResultMapId);
   	            if (ancestorObject != null) {
   	              if (newObject) {//是不是 嵌套的新对象
   	              
   	                linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
   	              }
   	              continue;
   	            }
   	          }
   	          final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
   	          final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
   	          //找嵌套对象,如果为null的话,会在getRowValue实例化
   	          Object rowValue = nestedResultObjects.get(combinedKey);
   	          boolean knownValue = rowValue != null;
   	          instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory
   	          if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
   	          	//通过prefix 把sql的字段映射到实体类里
   	          	//重新走getRowValue方法,按ResultMap的resultMapping  对嵌套对象赋值
   	            rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
   	            if (rowValue != null && !knownValue) {
   	              //把 嵌套对象 赋值到 父对象属性上
   	              linkObjects(metaObject, resultMapping, rowValue);
   	              foundValues = true;
   	            }
   	          }
   	        } catch (SQLException e) {
   	          throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
   	        }
   	      }
   	    }
   	    return foundValues;
   	  }

总结

其实这里的源码注释还是比较少的,但是从各方法跟各对象的命名 还是能知道大致意图的。利用debug跟耐心慢慢看,还是能看懂的!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值