首先,入口类 SimpleStatementHandler
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.<E>handleResultSets(statement);
}
进入mybatis默认的 DefaultResultSetHandler类 ,
handleResultSets方法 处理结果集的映射:
@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);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
其他的不管,重点看 方法 handleResultSet(rsw, resultMap, multipleResults, null);
是怎么把 一个个ResultMap类型的映射对象 转变成 java的具体对象。
具体的java对象是保存在 multipleResults中的,如 debug截图所示:
解析参数:
ResultSetWrapper rsw : 该参数中 包含了 配置在mapper.xml中的某个映射对象(resultMap或resultType)的 几乎所有信息。
class ResultSetWrapper { private final ResultSet resultSet; private final TypeHandlerRegistry typeHandlerRegistry; private final List<String> columnNames = new ArrayList<String>();--列名 private final List<String> classNames = new ArrayList<String>();--类路径名 private final List<JdbcType> jdbcTypes = new ArrayList<JdbcType>();--JdbcType类型列表 private final Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<String, Map<Class<?>, TypeHandler<?>>>();
debug得到的 ResultSetWrapper rsw 对象的内容如下:
开始重点分析:
类DefaultResultSetHandler的方法handleRowValues中的方法handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
不考虑嵌套(只考虑单个result模式下,怎么把sql得到的resultType或resultMap对象转化成具体的javaBean对象的,包括javaBean对象的字段,各个方法)。
获取单row的值:
DefaultResultSetHandler 的 getRowValue 方法
DefaultResultSetHandler 的 createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) 方法
因为mybatis dao层里面的都是接口,所以此时拿到
final Class<?> resultType = resultMap.getType();
里面返回的javaBean对象,
使用ObjectFactory工厂 以及resultType 里的类路径 创建类的实例。
DefaultObjectFactory
@Override public <T> T create(Class<T> type) { return create(type, null, null); }
此时创建的resultObject对象是一个 参数皆为空的对象,还需要赋值。
resultObject对象赋值的话,实现的是 接口
TypeHandler的 getResult(ResultSet rs, String columnName) 或 getResult(ResultSet rs, int columnIndex) 方法,
通过 列名或者列索引 查询得到结果集rs中 对应字段的值,赋值到resultObject对象的相应字段。
最后 回到类DefaultResultSetHandler 的
handleRowValuesForSimpleResultMap()方法的
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
保存映射得到的结果对象。
debug下去,把映射的结果集传回来:
closeResultSet(rsw.getResultSet());
关闭该行记录的rsw,
最终
return collapseSingleResultList(multipleResults);
类PreparedStatementHandler 的 return resultSetHandler.<E> handleResultSets(ps);
类SimpleExecutor的
return handler.<E>query(stmt, resultHandler);
closeStatement(stmt); 关闭 Statement
回到最外层的实现类 DefaultSqlSession
的 selectOne(String statement, Object parameter)
返回对象。 结束:
回过头来 看一下最重要的几行代码:
类DefaultResultSetHandler 中的:
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());
}
}
第一步:skipRows(rsw.getResultSet(), rowBounds); 根据rowBounds中的offset值 定位到指定的记录行
第二步:
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { 校验是否还有需要映射的记录
第三步:
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
确定映射使用的 resultMap 对象。
最复杂的一步:
Object rowValue = getRowValue(rsw, discriminatedResultMap); 对resultMap中的一行记录进行映射。(分两步:首先创建resultMap对应的 javaBean对象,然后给该javaBean对象的每个字段一一赋值)。
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;
}
Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null); 创建对象
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; 给创建的对象的每一行 赋值。