上一篇讲到PreparedStatementHandler的时候中间对参数处理的时候使用的是ParameterHandler;而在其查询最后也会使用一个resultSetHandler。本篇主要看看这两个类的逻辑
ParameterHandler
对SQL执行方法参数处理的顶级接口
/**
* A parameter handler sets the parameters of the {@code PreparedStatement}.
* 参数处理器接口
* @author Clinton Begin
*/
public interface ParameterHandler {
// 获得参数对象
Object getParameterObject();
// 设置PreparedStatement的占位符
void setParameters(PreparedStatement ps)
throws SQLException;
}
实现类
DefaultParameterHandler是ParameterHandler唯一的实现类
DefaultParameterHandler
实现 ParameterHandler 接口,默认 ParameterHandler 实现类
setParameters
是其主要处理参数的方法
但是仔细回想着,其实这一部分在SQL初始化的时候最后已经讲过了。
ParameterHandler进行参数替换
ResultSetHandler
对SQL执行结果的处理的顶级接口
/**
* java.sql.ResultSet 处理器接口
* @author Clinton Begin
*/
public interface ResultSetHandler {
// 处理 {@link java.sql.ResultSet} 成映射的对应的结果
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
// 处理 {@link java.sql.ResultSet} 成 Cursor 对象
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
// 暂时忽略,和存储过程相关
void handleOutputParameters(CallableStatement cs) throws SQLException;
}
实现类
DefaultResultSetHandler是ResultSetHandler唯一的实现类
DefaultResultSetHandler
实现 DefaultResultSetHandler接口,默认 DefaultResultSetHandler实现类
handleResultSets
//
// HANDLE RESULT SETS
// 处理 java.sql.ResultSet 结果集,转换成映射的对应结果
// 仅仅支持处理 Statement 和 PreparedStatement 返回的结果集,
// 也支持存储过程的 CallableStatement 返回的结果集。
// 而 CallableStatement 是支持返回多结果集的,这个大家要注意
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
// 多 ResultSet 的结果集合,每个 ResultSet 对应一个 Object 对象。
// 而实际上,每个 Object 是 List<Object> 对象。
// 在不考虑存储过程的多 ResultSet 的情况,普通的查询,实际就一个 ResultSet ,
// 也就是说,multipleResults 最多就一个元素。
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 获取第一个返回结果对象,并封装成结果结果对象包装类
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 从mappedStatement中获得结果的map
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
// 取得结果Map的总数,然后进行验证
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
// 获得resultMap
ResultMap resultMap = resultMaps.get(resultSetCount);
// 进行复制操作
handleResultSet(rsw, resultMap, multipleResults, null);
// 获得下一个封装对象
rsw = getNextResultSet(stmt);
// 清理上下文
cleanUpAfterHandlingResultSet();
// 索引增加
resultSetCount++;
}
// getResultSets 存储过程使用
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++;
}
}
// 如果是 multipleResults 单元素,则取首元素返回
return collapseSingleResultList(multipleResults);
}
在不考虑存储过程的多 ResultSet 的情况,一般的查询mappedStatement.getResultMaps()只会拿到一个结果集映射,而不是出现多种映射
整个逻辑可以被拆分成这样:
首先从Statement获得其结果集ResultSet,然后通过ResultSetWrapper对其进行包装。
然后从mappedStatement中获得其结果映射集合。
依次从映射集合中获取单独项,进行结果复制复制到multipleResults中。
如果有多个结果,但是只需要返回一个,则取第一个返回。
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 {
// 如果没有自定义的 resultHandler ,则创建默认的 DefaultResultHandler 对象
if (resultHandler == null) {
// 创建一个默认的结果处理器
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 处理 ResultSet 返回的每一行 Row
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 添加处理结果
multipleResults.add(defaultResultHandler.getResultList());
} else {
// 理 ResultSet 返回的每一行 Row
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()) {
// 校验不要使用 RowBounds
ensureNoRowBounds();
// 校验不要使用自定义的 resultHandler
checkResultHandler();
// 处理嵌套映射的结果
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
// 处理简单映射关系
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
进行参数处理的方法
最终都是使用handleRowValues进行参数替换的。我们看下简单的映射关系。
handleRowValuesForSimpleResultMap
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
// 创建 DefaultResultContext 对象
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
// 获得 ResultSet 对象,并跳到 rowBounds 指定的开始位置
ResultSet resultSet = rsw.getResultSet();
skipRows(resultSet, rowBounds);
// 循环
while (shouldProcessMoreRows(resultContext, rowBounds) // 是否还需要处理
&& !resultSet.isClosed() // 是否已经关闭
&& resultSet.next()) { // 是否结束
// 根据该行记录以及 ResultMap.discriminator ,决定映射使用的 ResultMap 对象
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 根据最终确定的 ResultMap 对 ResultSet 中的该行记录进行映射,得到映射后的结果对象
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// 将映射创建的结果对象添加到 ResultHandler.resultList 中保存
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
storeObject
将值保存到ResultHandler.resultList中
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
} else {
callResultHandler(resultHandler, resultContext, rowValue);
}
}
// 调用 ResultHandler ,进行结果的处理
@SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
// 设置结果对象到 resultContext 中
resultContext.nextResultObject(rowValue);
// 使用 ResultHandler 处理结果。
// 如果使用 DefaultResultHandler 实现类的情况,会将映射创建的结果对象添加到 ResultHandler.resultList 中保存
((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
// org/apache/ibatis/executor/result/DefaultResultHandler.java
@Override
public void handleResult(ResultContext<?> context) {
// 将当前结果,添加到结果数组中
list.add(context.getResultObject());
}
总结:
- ParameterHandler的方法其实在初始化SQL的过程中我们已经看过的,就不多介绍了。
- ResultSetHandler的整个逻辑的核心在handleResultSet上面(不考虑存储过程)其他的不过是数据获取和效验。
- 继续深扒整个方法嵌套是handleRowValues ->handleRowValuesForSimpleResultMap是进行最后数据复制的地方。
- 通过resolveDiscriminatedResultMap获得具体的映射对象,然后在getRowValue获得对应的值,然后在storeObject将值绑定到对应的DefaultResultHandler.list中
- 里面很多细节其实并没有说清,强烈建议边调试边查看。