Mybatis源码分析之结果封装ResultSetHandler和DefaultResultSetHandler
ResultSetHandler是一个接口,提供了两个函数分别用来处理普通操作和存储过程的结果,
源码如下:
/** * @author Clinton Begin */ public interface ResultSetHandler { <E> List<E> handleResultSets(Statement stmt) throws SQLException; void handleOutputParameters(CallableStatement cs) throws SQLException; }
ResultSetHandler的具体实现类是DefaultResultSetHandler,其实现的步骤就是将Statement执行后的结果集,按照Mapper文件中配置的ResultType或ResultMap来封装成对应的对象,最后将封装的对象返回即可,
DefaultResultSetHandler源码如下:
//ResultSetHandler具体实现类 public class DefaultResultSetHandler implements ResultSetHandler { private static final Object DEFERED = new Object(); private final Executor executor; private final Configuration configuration; private final MappedStatement mappedStatement; private final RowBounds rowBounds; private final ParameterHandler parameterHandler; private final ResultHandler<?> resultHandler; private final BoundSql boundSql; private final TypeHandlerRegistry typeHandlerRegistry; private final ObjectFactory objectFactory; private final ReflectorFactory reflectorFactory; // nested resultmaps // 此Map用来保存当前层级内部的结果对象(一对多关系的多方对象),key为combinedKey private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>(); // 此Map用来保存当前层级的根对象(一对多关系中的一方对象),key为absoluteKey private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>(); private final Map<String, String> ancestorColumnPrefix = new HashMap<String, String>(); // multiple resultsets private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>(); private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>(); private static class PendingRelation { public MetaObject metaObject; public ResultMapping propertyMapping; } public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) { this.executor = executor; this.configuration = mappedStatement.getConfiguration(); this.mappedStatement = mappedStatement; this.rowBounds = rowBounds; this.parameterHandler = parameterHandler; this.boundSql = boundSql; this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); this.objectFactory = configuration.getObjectFactory(); this.reflectorFactory = configuration.getReflectorFactory(); this.resultHandler = resultHandler; } // // HANDLE OUTPUT PARAMETER // //调用存储过程返回结果,将结果值放在参数中 @Override public void handleOutputParameters(CallableStatement cs) throws SQLException { final Object parameterObject = parameterHandler.getParameterObject(); final MetaObject metaParam = configuration.newMetaObject(parameterObject); final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); //循环处理每个参数 for (int i = 0; i < parameterMappings.size(); i++) { final ParameterMapping parameterMapping = parameterMappings.get(i); //判断参数的模式 if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) { if (ResultSet.class.equals(parameterMapping.getJavaType())) { handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam); } else { final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler(); metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1)); } } } } private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam) throws SQLException { try { final String resultMapId = parameterMapping.getResultMapId(); final ResultMap resultMap = configuration.getResultMap(resultMapId); final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory); final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration); handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null); metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList()); } finally { // issue #228 (close resultsets) closeResultSet(rs); } } // // HANDLE RESULT SETS // //对普通查询到的结果转换 @Override 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; //获取第一个结果值 ResultSetWrapper rsw = getFirstResultSet(stmt); //获得resultMap List<ResultMap> resultMaps = mappedStatement.getResultMaps(); //这边应该为1吧,一般resultMap为一个 int resultMapCount = resultMaps.size(); //判断是否有resultMap,没有的话抛出异常 validateResultMapsCount(rsw, resultMapCount); while (rsw != null && resultMapCount > resultSetCount) { //获得resultMap,实体类和表中数据字段的对应关系 ResultMap resultMap = resultMaps.get(resultSetCount); //将值设置成对应的resultmap对象 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); } //获得第一个值,并将值打包 private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException { ResultSet rs = stmt.getResultSet(); //结果集不为空 while (rs == null) { // move forward to get the first resultset in case the driver // doesn't return the resultset as the first result (HSQLDB 2.1) if (stmt.getMoreResults()) { rs = stmt.getResultSet(); } else { if (stmt.getUpdateCount() == -1) { // no more results. Must be no resultset break; } } } //将数据打包 return rs != null ? new ResultSetWrapper(rs, configuration) : null; } //获取下一个值,将值打包 private ResultSetWrapper getNextResultSet(Statement stmt) throws SQLException { // Making this method tolerant of bad JDBC drivers try { if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) { // Crazy Standard JDBC way of determining if there are more results if (!((!stmt.getMoreResults()) && (stmt.getUpdateCount() == -1))) { ResultSet rs = stmt.getResultSet(); return rs != null ? new ResultSetWrapper(rs, configuration) : null; } } } catch (Exception e) { // Intentionally ignored. } return null; } //关闭resultSet private void closeResultSet(ResultSet rs) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { // ignore } } private void cleanUpAfterHandlingResultSet() { nestedResultObjects.clear(); ancestorColumnPrefix.clear(); } //校验结果的resultMap,如果没有的话就抛出异常 private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) { if (rsw != null && resultMapCount < 1) { throw new ExecutorException("A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId() + "'. It's likely that neither a Result Type nor a Result Map was specified."); } } 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) { // 创建一个新对象 DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); //将查询到的每个字段和Bean实体中的属性对应起来,生成一个Result对象 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); //结果映射对象及值添加到multipleResults中 multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } } @SuppressWarnings("unchecked") private List<Object> collapseSingleResultList(List<Object> multipleResults) { return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults; } // // HANDLE ROWS FOR SIMPLE RESULTMAP // //操作列值 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); } } //判断记录行数 private void ensureNoRowBounds() { if (configuration.isSafeRowBoundsEnabled() && rowBounds != null && (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) { throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. " + "Use safeRowBoundsEnabled=false setting to bypass this check."); } } protected void checkResultHandler() { if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) { throw new ExecutorException("Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. " + "Use safeResultHandlerEnabled=false setting to bypass this check " + "or ensure your statement returns ordered data and set resultOrdered=true on it."); } } private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>(); //跳过RowBounds设置的offset值 skipRows(rsw.getResultSet(), rowBounds); //判断数据是否小于limit,如果小于limit的话就不断的循环取值 while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); Object rowValue = getRowValue(rsw, discriminatedResultMap); storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } } private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException { if (parentMapping != null) { linkToParents(rs, parentMapping, rowValue); } else { callResultHandler(resultHandler, resultContext, rowValue); } } @SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/) private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) { resultContext.nextResultObject(rowValue); ((ResultHandler<Object>)resultHandler).handleResult(resultContext); } private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException { //判断数据是否小于limit,小于返回true return !context.isStopped() && context.getResultCount() < rowBounds.getLimit(); } //跳过不需要的行,应该就是rowbounds设置的limit和offset private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException { if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) { if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) { rs.absolute(rowBounds.getOffset()); } } else { //跳过RowBounds中设置的offset条数据 for (int i = 0; i < rowBounds.getOffset(); i++) { rs.next(); } } } // // GET VALUE FROM ROW FOR SIMPLE RESULT MAP // private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); //结果的映射对象 Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null); if (resultObject != null && !typeHandlerRegistry.hasTypeHandler(resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(resultObject); boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty(); if (shouldApplyAutomaticMappings(resultMap, false)) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; foundValues = lazyLoader.size() > 0 || foundValues; resultObject = foundValues ? resultObject : null; return resultObject; } return resultObject; } //用于判断是否是bean实体变量和表中字段自动映射 private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) { if (resultMap.getAutoMapping() != null) { return resultMap.getAutoMapping(); } else { if (isNested) { return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior(); } else { return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior(); } } } // // PROPERTY MAPPINGS // 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; final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings(); 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(); // issue #377, call setter on nulls if (value != DEFERED && property != null && (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive()))) { metaObject.setValue(property, value); } if (value != null || value == DEFERED) { foundValues = true; } } } 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); // TODO is that OK? return DEFERED; } else { final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler(); final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix); return typeHandler.getResult(rs, column); } } // private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix); boolean foundValues = false; //获得列名 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; } } final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase()); 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); // issue #377, call setter on nulls if (value != null || configuration.isCallSettersOnNulls()) { if (value != null || !propertyType.isPrimitive()) { metaObject.setValue(property, value); } foundValues = true; } } } } return foundValues; } // MULTIPLE RESULT SETS private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException { CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn()); List<PendingRelation> parents = pendingRelations.get(parentKey); if (parents != null) { for (PendingRelation parent : parents) { if (parent != null && rowValue != null) { linkObjects(parent.metaObject, parent.propertyMapping, rowValue); } } } } private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping) throws SQLException { CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getColumn()); PendingRelation deferLoad = new PendingRelation(); deferLoad.metaObject = metaResultObject; deferLoad.propertyMapping = parentMapping; List<PendingRelation> relations = pendingRelations.get(cacheKey); // issue #255 if (relations == null) { relations = new ArrayList<DefaultResultSetHandler.PendingRelation>(); pendingRelations.put(cacheKey, relations); } relations.add(deferLoad); ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet()); if (previous == null) { nextResultMaps.put(parentMapping.getResultSet(), parentMapping); } else { if (!previous.equals(parentMapping)) { throw new ExecutorException("Two different properties are mapped to the same resultSet"); } } } private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names, String columns) throws SQLException { CacheKey cacheKey = new CacheKey(); cacheKey.update(resultMapping); if (columns != null && names != null) { String[] columnsArray = columns.split(","); String[] namesArray = names.split(","); for (int i = 0 ; i < columnsArray.length ; i++) { Object value = rs.getString(columnsArray[i]); if (value != null) { cacheKey.update(namesArray[i]); cacheKey.update(value); } } } return cacheKey; } // // INSTANTIATION & CONSTRUCTOR MAPPING // //创建结果对象 private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { 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())) { //获取配置的resultMap的字段与表中数据的映射关系 final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings(); for (ResultMapping propertyMapping : propertyMappings) { // issue gcode #109 && issue #149 if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) { 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(); //通过反射获取结果对象 final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory); final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings(); if (typeHandlerRegistry.hasTypeHandler(resultType)) { //基本类型 return createPrimitiveResultObject(rsw, resultMap, columnPrefix); } else if (!constructorMappings.isEmpty()) { //有参数构造函数 return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix); } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) { //普通的bean类型 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); } //有参数构造函数 Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) { boolean foundValues = false; for (ResultMapping constructorMapping : constructorMappings) { final Class<?> parameterType = constructorMapping.getJavaType(); final String column = constructorMapping.getColumn(); final Object value; try { 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)); } } catch (ResultMapException e) { throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e); } catch (SQLException e) { throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e); } constructorArgTypes.add(parameterType); constructorArgs.add(value); foundValues = value != null || foundValues; } return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null; } //自动映射 private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException { for (Constructor<?> constructor : resultType.getDeclaredConstructors()) { if (typeNames(constructor.getParameterTypes()).equals(rsw.getClassNames())) { boolean foundValues = false; for (int i = 0; i < constructor.getParameterTypes().length; i++) { Class<?> parameterType = constructor.getParameterTypes()[i]; String columnName = rsw.getColumnNames().get(i); TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName); Object value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(columnName, columnPrefix)); constructorArgTypes.add(parameterType); constructorArgs.add(value); foundValues = value != null || foundValues; } return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null; } } throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames()); } private List<String> typeNames(Class<?>[] parameterTypes) { List<String> names = new ArrayList<String>(); for (Class<?> type : parameterTypes) { names.add(type.getName()); } return names; } //创建原型结果 private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException { final Class<?> resultType = resultMap.getType(); final String columnName; if (!resultMap.getResultMappings().isEmpty()) { final List<ResultMapping> resultMappingList = resultMap.getResultMappings(); final ResultMapping mapping = resultMappingList.get(0); columnName = prependPrefix(mapping.getColumn(), columnPrefix); } else { columnName = rsw.getColumnNames().get(0); } final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName); return typeHandler.getResult(rsw.getResultSet(), columnName); } // // NESTED QUERY // private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix) throws SQLException { final String nestedQueryId = constructorMapping.getNestedQueryId(); final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId); final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType(); final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping, nestedQueryParameterType, columnPrefix); Object value = null; if (nestedQueryParameterObject != null) { final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject); final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql); final Class<?> targetType = constructorMapping.getJavaType(); final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql); value = resultLoader.loadResult(); } return value; } //得到嵌套查询值 private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException { final String nestedQueryId = propertyMapping.getNestedQueryId(); final String property = propertyMapping.getProperty(); final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId); final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType(); final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix); Object value = null; if (nestedQueryParameterObject != null) { final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject); final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql); final Class<?> targetType = propertyMapping.getJavaType(); if (executor.isCached(nestedQuery, key)) { //如果已经有一级缓存了,则延迟加载(实际上deferLoad方法中可以看到则是立即加载) executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType); value = DEFERED; } else { //否则lazyLoader.addLoader 需要延迟加载则addLoader //或者ResultLoader.loadResult 不需要延迟加载则立即加载 final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql); if (propertyMapping.isLazy()) { lazyLoader.addLoader(property, metaResultObject, resultLoader); value = DEFERED; } else { value = resultLoader.loadResult(); } } } return value; } private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException { if (resultMapping.isCompositeResult()) { return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix); } else { return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix); } } private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException { final TypeHandler<?> typeHandler; if (typeHandlerRegistry.hasTypeHandler(parameterType)) { typeHandler = typeHandlerRegistry.getTypeHandler(parameterType); } else { typeHandler = typeHandlerRegistry.getUnknownTypeHandler(); } return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix)); } private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType, String columnPrefix) throws SQLException { final Object parameterObject = instantiateParameterObject(parameterType); final MetaObject metaObject = configuration.newMetaObject(parameterObject); boolean foundValues = false; for (ResultMapping innerResultMapping : resultMapping.getComposites()) { final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty()); final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType); final Object propValue = typeHandler.getResult(rs, prependPrefix(innerResultMapping.getColumn(), columnPrefix)); // issue #353 & #560 do not execute nested query if key is null if (propValue != null) { metaObject.setValue(innerResultMapping.getProperty(), propValue); foundValues = true; } } return foundValues ? parameterObject : null; } private Object instantiateParameterObject(Class<?> parameterType) { if (parameterType == null) { return new HashMap<Object, Object>(); } else { return objectFactory.create(parameterType); } } // // DISCRIMINATOR // public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException { Set<String> pastDiscriminators = new HashSet<String>(); Discriminator discriminator = resultMap.getDiscriminator(); while (discriminator != null) { final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix); final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value)); if (configuration.hasResultMap(discriminatedMapId)) { resultMap = configuration.getResultMap(discriminatedMapId); Discriminator lastDiscriminator = discriminator; discriminator = resultMap.getDiscriminator(); if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) { break; } } else { break; } } return resultMap; } private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException { final ResultMapping resultMapping = discriminator.getResultMapping(); final TypeHandler<?> typeHandler = resultMapping.getTypeHandler(); return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix)); } private String prependPrefix(String columnName, String prefix) { if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) { return columnName; } return prefix + columnName; } // // HANDLE NESTED RESULT MAPS // //生成嵌套对象值 private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { //创建默认结果上下文 final DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>(); //跳过rowBounds指定offset行偏移量 skipRows(rsw.getResultSet(), rowBounds); Object rowValue = null; //如何定义应该处理:上下文没有主动停止,结果集还有记录,且上下文中结果对象数量不足时,应该继续处理 while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { // 解决鉴别过的结果映射,逻辑如下: // 获取结果映射中的鉴别器,通过鉴别指定字段通过配置对象获取对应的另一个结果映射,循环往复, // 直到找不到鉴别器为止,返回最终的结果映射 final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); // 创建缓存key,如何创建? 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, rowKey, null, partialObject); } else { rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, 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()); } } // // GET VALUE FROM ROW FOR NESTED RESULT MAP // // 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; if (resultObject != null) { final MetaObject metaObject = configuration.newMetaObject(resultObject); putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix); 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().isEmpty(); if (shouldApplyAutomaticMappings(resultMap, true)) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues; putAncestor(absoluteKey, resultObject, resultMapId, columnPrefix); foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues; ancestorObjects.remove(absoluteKey); foundValues = lazyLoader.size() > 0 || foundValues; resultObject = foundValues ? resultObject : null; } if (combinedKey != CacheKey.NULL_CACHE_KEY) { nestedResultObjects.put(combinedKey, resultObject); } } return resultObject; } private void putAncestor(CacheKey rowKey, Object resultObject, String resultMapId, String columnPrefix) { if (!ancestorColumnPrefix.containsKey(resultMapId)) { ancestorColumnPrefix.put(resultMapId, columnPrefix); } ancestorObjects.put(rowKey, resultObject); } // // NESTED RESULT MAP (JOIN MAPPING) // 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) { linkObjects(metaObject, resultMapping, ancestorObject); // issue #385 } } else { rowKey = createRowKey(nestedResultMap, rsw, columnPrefix); final CacheKey combinedKey = combineKeys(rowKey, parentRowKey); Object rowValue = nestedResultObjects.get(combinedKey); boolean knownValue = (rowValue != null); instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw.getResultSet())) { rowValue = getRowValue(rsw, nestedResultMap, combinedKey, rowKey, 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; } private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) { final StringBuilder columnPrefixBuilder = new StringBuilder(); if (parentPrefix != null) { columnPrefixBuilder.append(parentPrefix); } if (resultMapping.getColumnPrefix() != null) { columnPrefixBuilder.append(resultMapping.getColumnPrefix()); } return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH); } private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSet rs) throws SQLException { Set<String> notNullColumns = resultMapping.getNotNullColumns(); boolean anyNotNullColumnHasValue = true; if (notNullColumns != null && !notNullColumns.isEmpty()) { anyNotNullColumnHasValue = false; for (String column: notNullColumns) { rs.getObject(prependPrefix(column, columnPrefix)); if (!rs.wasNull()) { anyNotNullColumnHasValue = true; break; } } } return anyNotNullColumnHasValue; } private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix) throws SQLException { ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId); return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix); } // // UNIQUE RESULT KEY // private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException { final CacheKey cacheKey = new CacheKey(); cacheKey.update(resultMap.getId()); List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap); if (resultMappings.size() == 0) { if (Map.class.isAssignableFrom(resultMap.getType())) { createRowKeyForMap(rsw, cacheKey); } else { createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix); } } else { createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix); } return cacheKey; } private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) { if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) { CacheKey combinedKey; try { combinedKey = rowKey.clone(); } catch (CloneNotSupportedException e) { throw new ExecutorException("Error cloning cache key. Cause: " + e, e); } combinedKey.update(parentRowKey); return combinedKey; } return CacheKey.NULL_CACHE_KEY; } private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) { List<ResultMapping> resultMappings = resultMap.getIdResultMappings(); if (resultMappings.size() == 0) { resultMappings = resultMap.getPropertyResultMappings(); } return resultMappings; } private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, List<ResultMapping> resultMappings, String columnPrefix) throws SQLException { for (ResultMapping resultMapping : resultMappings) { if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) { // Issue #392 final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId()); createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey, nestedResultMap.getConstructorResultMappings(), prependPrefix(resultMapping.getColumnPrefix(), columnPrefix)); } else if (resultMapping.getNestedQueryId() == null) { final String column = prependPrefix(resultMapping.getColumn(), columnPrefix); final TypeHandler<?> th = resultMapping.getTypeHandler(); List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix); // Issue #114 if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) { final Object value = th.getResult(rsw.getResultSet(), column); if (value != null) { cacheKey.update(column); cacheKey.update(value); } } } } } private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey, String columnPrefix) throws SQLException { final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory); List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix); for (String column : unmappedColumnNames) { String property = column; if (columnPrefix != null && !columnPrefix.isEmpty()) { // When columnPrefix is specified, ignore columns without the prefix. if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) { property = column.substring(columnPrefix.length()); } else { continue; } } if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) { String value = rsw.getResultSet().getString(column); if (value != null) { cacheKey.update(column); cacheKey.update(value); } } } } private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException { List<String> columnNames = rsw.getColumnNames(); for (String columnName : columnNames) { final String value = rsw.getResultSet().getString(columnName); if (value != null) { cacheKey.update(columnName); cacheKey.update(value); } } } private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) { final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); if (collectionProperty != null) { final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty); targetMetaObject.add(rowValue); } else { metaObject.setValue(resultMapping.getProperty(), rowValue); } } private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) { 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); 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源码分析之结果封装ResultSetHandler和DefaultResultSetHandler的更多相关文章
- mybatis 源码分析(八)ResultSetHandler 详解
本篇博客就是 myabtis 系列的最后一篇了,还剩 ResultSetHandler 没有分析:作为整个 mybatis 最复杂最繁琐的部分,我不打算按步骤一次详解,因为里面的主要内容就是围绕 re ...
- 精尽MyBatis源码分析 - SQL执行过程(三)之 ResultSetHandler
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis源码分析-SQL语句执行的完整流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- 【MyBatis源码分析】select源码分析及小结
示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...
- Mybatis源码分析-StatementHandler
承接前文Mybatis源码分析-BaseExecutor,本文则对通过StatementHandler接口完成数据库的CRUD操作作简单的分析 StatementHandler#接口列表 //获取St ...
- MyBatis 源码分析 - 插件机制
1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- Mybatis源码分析
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- Mybatis源码分析之SqlSession和Excutor(二)
通过上一篇文章的分析我们,我初步了解了它是如何创建sessionFactory的(地址:Mybatis源码分析之SqlSessionFactory(一)), 今天我们分析下Mybatis如何创建Sql ...
随机推荐
- Linux必备操作vim
vim被称作为编辑器之神,那么在我们操作linux系统时,进行编辑操作有没有感觉心有余而力不足?今天我讲自己总结的一些vim的操作命令和大家进行一下分享,有不足之处还请指出. vim的三种模式大家还记 ...
- OVF文件考究
一.什么是OVF文件 开源虚拟化格式OVF(不同于小写的ovf)文件是一种开源的文件规范,它描述了一个开源.安全.有效.可拓展的便携式虚拟打包以及软件分布格式,它一般有几个部分组成,分别是o ...
- SecureFX连接Linux后文件夹中文乱码问题解决(转)
在使用SecureFX 连接Linux 时,发现文件夹显示乱码,一直尝试各种配置,现将方法整理一下!供大家参考! 首先在选项中设置字符编码为UTF-8 然后在全局选项中找到Securefx的配置文件 ...
- 三种方法,刷新 Android 的 MediaStore!让你保存的图片立即出现在相册里!
公众号原标题:测试:"系统相册里怎么看不到我刚保存的图片,是我操作不对吗?" 一.序 Hi,大家好,我是承香墨影! App 内,创建一个文件并保存文件到本地的需求,是很常见的 I/ ...
- 欢迎大家来到DevLegal的博客
申明:以下博文欢迎转载,转载请注明出处和作者 若非作者原创,则会标记出处与原作者,其余则为原创. 本人在校大学僧一枚,软件工程专业,希望通过将自己的学习心得与体会写出来,勉励自己学习,同时与大家一起分 ...
- Linux 管理软件
公司的openfire先前运行在windows上的,但由于在windows上openfire内存机制问题,最多只能占用2GB内存,且时间稍微长久一些就会自动挂掉,用户无法登陆和连接,因此迁移到了Cen ...
- Python 元组内置函数
Python元组包含了以下内置函数 序号 方法及描述 1 cmp(tuple1, tuple2)比较两个元组元素. 2 len(tuple)计算元组元素个数. 3 max(tuple)返回元组中元素最 ...
- 用Matlab画直方图
简介 本文介绍如何使用matlab定制自己的直方图. 关键 使用Matlab的 bar() 函数创建柱状图 bar() 画的bin的高度跟数据相关 bar() 数据每一列一个group,有几列数据就画 ...
- 六星经典CSAPP-笔记(7)加载与链接(上)
六星经典CSAPP-笔记(7)加载与链接 1.对象文件(Object File) 1.1 文件类型 对象文件有三种形式: 可重定位对象文件(Relocatable object file):包含二进制 ...
- JVM:类的生命周期
类的生命周期 综述 1. 只有当一个类被切实使用到的时候才会被加载到虚拟机中(例如:new, 方法调用, A a = null;不算) 2. 若在加载一个类的过程中,有其他类被切实使用到, ...