【福利】关注微信公众号:深夜程猿,回复关键字即可获取学习视频、简历模版
Mybatis支持多结果集,也就是结果集中的元素也可以是结果集,返回结果集的时候会调用相应的结果集处理器来处理结果集。我们来从源码角度看看具体的实现原理
首先,在查询操作,执行sql语句返回查询结果集后,调用默认的结果集处理器handleResultSets方法
DefaultResultSetHandler#handleResultSets
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;
// 获取第一个结果集,如果没有结果集,那么返回null
// 获取第一个结果集在于知道sql语句要操作到哪些元素数据(表的列),会获取到元数据名称、Java数据类型、JDBC数据类型
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 获取执行的sql配置的resultMap
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
// 一个resultMap对应一个结果集,依次遍历resultMap并处理结果集
while (rsw != null && resultMapCount > resultSetCount) {// 从条件可以看出,结果集个数和resultMap数量一样
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);
}
复制代码
我们看一下是怎么获取第一个结果集的
DefaultResultSetHandler#getFirstResultSet
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
ResultSet rs = stmt.getResultSet();
while (rs == null) {
// 没有结果集,也许是数据库驱动还没有返回第一个结果集
if (stmt.getMoreResults()) {
// 尝试再一次获取结果集
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
//rs == null && stmt.getUpdateCount() == -1表示驱动已经返回,没有更多结果,没有结果集
break;
}
}
}
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
复制代码
ResultSetWrapper#构造函数
// 封装结果集
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
super();
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;
final ResultSetMetaData metaData = rs.getMetaData();
final int columnCount = metaData.getColumnCount();
// 设置结果集的元数据
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));
}
}
复制代码
我们继续看下handleResultSet(rsw, resultMap, multipleResults, null);
的具体实现
DefaultResultSetHandler #handleResultSet
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());
}
}
复制代码
接着看handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
的实现
DefaultResultSetHandler#handleRowValues
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) { // 判断resultMap是否有嵌套的resultMap
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
复制代码
先看下没有嵌套resultMap的处理逻辑handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
DefaultResultSetHandler#handleRowValuesForSimpleResultMap
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);
// 处理行数据,并封装成指定的resultType
Object rowValue = getRowValue(rsw, discriminatedResultMap);
// 缓存对象,修改rowBounds的值
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
复制代码
再往下分析怎么获取行数据并封装成指定的resultType
DefaultResultSetHandler#getRowValue
// 获取行数据值
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())) {
// 行数据对象不是null,并且没有结果类型处理器
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
// 应用resultMap的属性映射配置,为行数据对象设置从数据库获取回来的值
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
}
// 返回处理过的行数据对象
return rowValue;
}
复制代码
简单分析了结果集的处理原理,它基本步骤:
- 解析SQL语句
- 执行SQL语句
- 根据SQL映射配置,比如resultMap或者resulType,resultSets等来对步骤2获取回来的结果集处理
- 返回处理过的结果集