转载自 mybatis源码阅读(七) ---ResultSetHandler了解一下
1、MetaObject
MetaObject用于反射创建对象、反射从对象中获取属性值、反射给对象设置属性值,参数设置和结果封装,用的都是这个MetaObject提供的功能。
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {if (object == null) {return SystemMetaObject.NULL_META_OBJECT;} else {return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);}
}
public Object getValue(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return null;} else {return metaValue.getValue(prop.getChildren());}} else {return objectWrapper.get(prop);}
}public void setValue(String name, Object value) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {if (value == null && prop.getChildren() != null) {// don't instantiate child path if value is nullreturn;} else {metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);}}metaValue.setValue(prop.getChildren(), value);} else {objectWrapper.set(prop, value);}
}
Object object:要反射的对象,比如Student。
ObjectFactory objectFactory:通过Class对象反射创建对象实例的工厂类,比如创建一个User对象。
ObjectWrapperFactory :对目标对象进行包装,比如可以将Properties对象包装成为一个Map并返回Map对象。
ReflectorFactory :为了避免多次反射同一个Class对象,ReflectorFactory提供了Class对象的反射结果缓存。
getValue(String name):属性取值。
setValue(String name, Object value):属性赋值。
2、结果封装实现原理
Mybatis的结果封装,分为两种,一种是有ResultMap映射表,明确定义了结果集列名与对象属性名的配对关系,另外一种是对象类型,没有明确定义结果集列名与对象属性名的配对关系,如resultType是User对象。
<resultMap type="userT" id="userResult"><id property="id" column="t_id"/><result property="name" column="name" />
</resultMap><select id="findUserById" resultMap="userResult">select * from m_user where id = #{id}
</select>
原理非常简单:使用ObjectFactory ,创建一个userT对象实例。
userT.setId(resultSet.getInt("t_id"));
userT.setName(resultSet.getString("name"));
如果是对象类型,如User对象类似,原理也非常简单。
<select id="findUserById" resultType="com.lpf.entity.User">select * from m_user where id = #{id}
</select>
原理:使用ObjectFactory ,创建一个User对象实例。
user.setId(resultSet.getInt("id"));user.setName(resultSet.getString("name"));
3、DefaultResultSetHandler
DefaultResultSetHandler继承了,ResultSetHandler是一个接口,提供了两个函数分别用来处理普通操作和存储过程的结果,
源码如下:
/*** @author Clinton Begin*/
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;}
DefaultResultSetHandler,其实现的步骤就是将Statement执行后的结果集,按照Mapper文件中配置的ResultType或ResultMap来封装成对应的对象,最后将封装的对象返回即可,
结果封装实现原理
DefaultResultSetHandler部分源码如下:
public class DefaultResultSetHandler implements ResultSetHandler {private static final Object DEFERED = new Object();// 此Map用来保存当前层级内部的结果对象(一对多关系的多方对象),key为combinedKeyprivate final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();// 此Map用来保存当前层级的根对象(一对多关系中的一方对象),key为absoluteKeyprivate final Map<String, Object> ancestorObjects = new HashMap<String, Object>();private Object previousRowValue;// multiple resultsetsprivate final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();// Cached Automappingsprivate final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<String, List<UnMappedColumnAutoMapping>>();// temporary marking flag that indicate using constructor mapping (use field to reduce memory usage)private boolean useConstructorMappings;private final PrimitiveTypes primitiveTypes;private static class PendingRelation {public MetaObject metaObject;public ResultMapping propertyMapping;}/*** 调用存储过程返回结果,将结果值放在参数中* @param cs* @throws SQLException*/@Overridepublic 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));}}}}/*** 对普通查询到的结果转换* @param stmt* @return* @throws SQLException*/@Overridepublic 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);//获得resultMapList<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++;}//获得resultSetsString[] resultSets = mappedStatement.getResultSets();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 resultsetbreak;}}}return rs != null ? new ResultSetWrapper(rs, configuration) : null;}//获取下一个值,将值打包private ResultSetWrapper getNextResultSet(Statement stmt) throws SQLException {// Making this method tolerant of bad JDBC driverstry {if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {// Crazy Standard JDBC way of determining if there are more resultsif (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {ResultSet rs = stmt.getResultSet();if (rs == null) {return getNextResultSet(stmt);} else {return new ResultSetWrapper(rs, configuration);}}}} catch (Exception e) {// Intentionally ignored.}return null;}//关闭resultSetprivate void closeResultSet(ResultSet rs) {try {if (rs != null) {rs.close();}} catch (SQLException e) {// ignore}}//校验结果的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());}}//操作列值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 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.");}}private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();skipRows(rsw.getResultSet(), rowBounds);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 Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {final ResultLoaderMap lazyLoader = new ResultLoaderMap();Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final MetaObject metaObject = configuration.newMetaObject(rowValue);boolean foundValues = this.useConstructorMappings;if (shouldApplyAutomaticMappings(resultMap, false)) {foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;}foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}return rowValue;}private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {if (propertyMapping.getNestedQueryId() != null) {//关联查询// 执行另外一个select查询,把查询结果赋值给属性值,比如Student对象的teacher属性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 Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {this.useConstructorMappings = false; // reset previous mapping resultfinal List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();final List<Object> constructorArgs = new ArrayList<Object>();//结果对象Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {//获取配置的resultMap的字段与表中数据的映射关系final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {// issue gcode #109 && issue #149if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);break;}}}this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping resultreturn resultObject;}//得到嵌套查询值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 {// ResultLoader保存了关联查询所需要的所有信息final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);if (propertyMapping.isLazy()) {// 执行延迟加载// 语意:resultLoader的查询结果将赋值给metaResultObject源对象的property属性,resultLoader的查询参数值来自于metaResultObject源对象属性中。// 举例:查询Teacher,赋值给Student的teacher属性,参数来自于查询Student的ResultSet的teacher_id列的值。// 由于需要执行延迟加载,将查询相关信息放入缓存,但不执行查询,使用该属性时,自动触发加载操作。lazyLoader.addLoader(property, metaResultObject, resultLoader);value = DEFERED;} else {// 不执行延迟加载,立即查询并赋值value = resultLoader.loadResult();}}}return value;}//生成嵌套对象值 一对多查询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 && #542if (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;}}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);applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);ancestorObjects.remove(resultMapId);} else {final ResultLoaderMap lazyLoader = new ResultLoaderMap();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);// 解析NestedResultMappings并封装结果,赋值给源对象的关联查询属性上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;}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);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);Object rowValue = nestedResultObjects.get(combinedKey);boolean knownValue = rowValue != null;instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatoryif (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {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;}}