轉(zhuǎn)載自??mybatis源碼閱讀(七) ---ResultSetHandler了解一下
1、MetaObject
MetaObject用于反射創(chuàng)建對象、反射從對象中獲取屬性值、反射給對象設(shè)置屬性值,參數(shù)設(shè)置和結(jié)果封裝,用的都是這個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對象反射創(chuàng)建對象實例的工廠類,比如創(chuàng)建一個User對象。
ObjectWrapperFactory :對目標對象進行包裝,比如可以將Properties對象包裝成為一個Map并返回Map對象。
ReflectorFactory :為了避免多次反射同一個Class對象,ReflectorFactory提供了Class對象的反射結(jié)果緩存。
getValue(String name):屬性取值。
setValue(String name, Object value):屬性賦值。
2、結(jié)果封裝實現(xiàn)原理
Mybatis的結(jié)果封裝,分為兩種,一種是有ResultMap映射表,明確定義了結(jié)果集列名與對象屬性名的配對關(guān)系,另外一種是對象類型,沒有明確定義結(jié)果集列名與對象屬性名的配對關(guān)系,如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 ,創(chuàng)建一個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 ,創(chuàng)建一個User對象實例。
user.setId(resultSet.getInt("id"));user.setName(resultSet.getString("name"));
3、DefaultResultSetHandler
DefaultResultSetHandler繼承了,ResultSetHandler是一個接口,提供了兩個函數(shù)分別用來處理普通操作和存儲過程的結(jié)果,
源碼如下:
/*** @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,其實現(xiàn)的步驟就是將Statement執(zhí)行后的結(jié)果集,按照Mapper文件中配置的ResultType或ResultMap來封裝成對應(yīng)的對象,最后將封裝的對象返回即可,
結(jié)果封裝實現(xiàn)原理
DefaultResultSetHandler部分源碼如下:
public class DefaultResultSetHandler implements ResultSetHandler {private static final Object DEFERED = new Object();// 此Map用來保存當(dāng)前層級內(nèi)部的結(jié)果對象(一對多關(guān)系的多方對象),key為combinedKeyprivate final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>();// 此Map用來保存當(dāng)前層級的根對象(一對多關(guān)系中的一方對象),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;}/*** 調(diào)用存儲過程返回結(jié)果,將結(jié)果值放在參數(shù)中* @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));}}}}/*** 對普通查詢到的結(jié)果轉(zhuǎn)換* @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;//獲取第一個結(jié)果值ResultSetWrapper rsw = getFirstResultSet(stmt);//獲得resultMapList<ResultMap> resultMaps = mappedStatement.getResultMaps();//這邊應(yīng)該為1吧,一般resultMap為一個int resultMapCount = resultMaps.size();//判斷是否有resultMap,沒有的話拋出異常validateResultMapsCount(rsw, resultMapCount);while (rsw != null && resultMapCount > resultSetCount) {//獲得resultMap,實體類和表中數(shù)據(jù)字段的對應(yīng)關(guān)系ResultMap resultMap = resultMaps.get(resultSetCount);//將值設(shè)置成對應(yīng)的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;}//關(guān)閉resultSetprivate void closeResultSet(ResultSet rs) {try {if (rs != null) {rs.close();}} catch (SQLException e) {// ignore}}//校驗結(jié)果的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實體中的屬性對應(yīng)起來,生成一個Result對象handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);//結(jié)果映射對象及值添加到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);}}//判斷記錄行數(shù)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) {//關(guān)聯(lián)查詢// 執(zhí)行另外一個select查詢,把查詢結(jié)果賦值給屬性值,比如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);}}//創(chuàng)建結(jié)果對象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>();//結(jié)果對象Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {//獲取配置的resultMap的字段與表中數(shù)據(jù)的映射關(guān)系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)) {//如果已經(jīng)有一級緩存了,則延遲加載(實際上deferLoad方法中可以看到則是立即加載)executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);value = DEFERED;} else {// ResultLoader保存了關(guān)聯(lián)查詢所需要的所有信息final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);if (propertyMapping.isLazy()) {// 執(zhí)行延遲加載// 語意:resultLoader的查詢結(jié)果將賦值給metaResultObject源對象的property屬性,resultLoader的查詢參數(shù)值來自于metaResultObject源對象屬性中。// 舉例:查詢Teacher,賦值給Student的teacher屬性,參數(shù)來自于查詢Student的ResultSet的teacher_id列的值。// 由于需要執(zhí)行延遲加載,將查詢相關(guān)信息放入緩存,但不執(zhí)行查詢,使用該屬性時,自動觸發(fā)加載操作。lazyLoader.addLoader(property, metaResultObject, resultLoader);value = DEFERED;} else {// 不執(zhí)行延遲加載,立即查詢并賦值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;// 解決鑒別過的結(jié)果映射,邏輯如下:// 獲取結(jié)果映射中的鑒別器,通過鑒別指定字段通過配置對象獲取對應(yīng)的另一個結(jié)果映射,循環(huán)往復(fù),// 直到找不到鑒別器為止,返回最終的結(jié)果映射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并封裝結(jié)果,賦值給源對象的關(guān)聯(lián)查詢屬性上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;}}
?
總結(jié)
以上是生活随笔為你收集整理的mybatis源码阅读(七) ---ResultSetHandler了解一下的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。