您的位置:首页 > 数据库

mybatis源码学习之执行过程分析(5)——sql执行后ResultSet的处理及结果返回

2017-01-04 19:16 906 查看

mybatis源码学习及分析之执行过程分析(5)——返回结果的处理

上一篇中分析了sql语句的创建和执行过程,使用jdbc时,执行完sql后会返回ResultSet,然后我们会通过getInteger()、getString()等方法拿到数据。而使用Mybatis中我们可以直接将结果转换为POJO对象,下面就来看看mybatis是如何封装ResultSet的。

PreparedStatementHandler.java

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
//在这里开始结果处理
return resultSetHandler.<E> handleResultSets(ps);
}


这里用到了ResultSetHandler。



DefaultResultSetHandler.java

public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mapdpedStatement.getId());

final List<Object> multipleResults = new ArrayList<Object>();

int resultSetCount = 0;
//获取ResultSet并包装为ResultSetWrapper
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++;
}

String[] 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 {
//JDBC中的代码,在这里拿到了ResultSet
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;
}
}
}
//将ResultSet包装为ResultSetWrapper
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}


当前调用栈信息:



当ResultSet不为空时,也就是查到了结果,通过rs和Configuration实例化了ResultSetWrapper。

public 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>();
private final Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<String, Map<Class<?>, TypeHandler<?>>>();
private Map<String, List<String>> mappedColumnNamesMap = new HashMap<String, List<String>>();
private Map<String, List<String>> unMappedColumnNamesMap = new HashMap<String, List<String>>();

public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
super();
//从configuration中拿到了typeHandlerRegistry
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;

//拿到了列信息
final int columnCount = metaData.getColumnCount();
//将每一列的名称、jdbc类型、java类型分别保存在三个ArrayList中。
for (int i = 1; i <= columnCount; i++) {
columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
classNames.add(metaData.getColumnClassName(i));
}
}
。。。
}


当前调用栈如下图:



返回的ResultSetWrapper信息如图:



到这里,我们的调用栈就返回到了
DefaultResultHandler#handleResultSets(Statement stmt)


接下来通过mappedStatement拿到了xml中配置的ResultMap。



可以看到ResultMap是我们将jdbc类型数据映射为POJO对象的重要手段。

validateResultMapsCount(rsw, resultMapCount);


对ResultMap进行校验,当查询返回的ResultMap数量小于1时,说明没有找到对应的ResultType或者ResultMap可以将结果映射出来,在这里就会抛出
ExecutorException
异常。

接下来重要的操作就是
handleResultSet(rsw, resultMap, multipleResults, null);
这里开始对结果集进行封装。

DefaultResultSetHandler.java

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);
//处理行信息
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
multipleResults.add(defaultResultHandler.getResultList());
} else {
//调用
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
closeResultSet(rsw.getResultSet());
}
}

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);
//调用getRowValue
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();
//创建了User
Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null);
if (resultObject != null && !hasTypeHandlerForResultObject(rsw, 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;
}

//调用User的setter方法为User实例设置信息
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) {
//getPropertyMappingValue在这里对了数据转换
Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
// issue #541 make property optional
final String property = propertyMapping.getProperty();
if (property == null) {
continue;
} else if (value == DEFERED) {
foundValues = true;
continue;
}
if (value != null) {
foundValues = true;
}
if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
// gcode issue #377, call setter on nulls (value is not 'found')
//在这里使用了setter方法设置值
metaObject.setValue(property, value);
}
}
}
return foundValues;
}




可以看到调用了User的setName。



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 {
//typeHandler
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
//数据库表的列名
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
//得到数据库中信息
return typeHandler.getResult(rs, column);
}
}


当所有的值都设置完成后,已经得到了我们需要的POJO类信息,调用栈开始出栈操作,方法return。



至此,结果封装完成,所有调用栈开始出栈操作,最后返回我们需要的User。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 mybatis sql
相关文章推荐