在前一篇文章中,笔者补上了一篇文章,在那篇文章中,主要说了关于SQL语句的执行流程,当SQL执行完成后,那么肯定会返回一个结果集,对于这样的结果集是需要做一个映射的,就譬如你所返回的数据是表中的数据,但是要映射成Java中的实体类对象,便需要进行映射处理。
说起来很抽象,那么就不多说了,还是直接进入主题,来看看在源码中是怎么实现的。
在进入正文之前,还需要再回顾一下关于结果集映射的入口代码:
@Override
public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行PreparedStatement,也就是执行SQL语句
ps.execute();
// 处理结果集
return resultSetHandler.handleResultSets(ps);
}
在上面的代码中可以看待处理结果集的入口的方法是handleResultSets这个方法。那么就直接进去看看方法中的代码是怎么实现的,代码如下:
@Override
public List
上面的代码还是挺复杂的,但是本节,首先看看getFirstResultSet(stmt)方法的实现:
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 resultset
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)方法进入,来看循环处理每个ResultMap到底是如何进行处理的:
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List 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);
// 处理行数据,其实就是完成结果映射
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());
}
}
先简单说下这段代码的逻辑功能:
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);
}
}
这里简单的说下简单结果集映射的实现,代码如下:
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
ResultHandler> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
DefaultResultContext resultContext = new DefaultResultContext<>();
// 获取结果集信息
ResultSet resultSet = rsw.getResultSet();
// 使用rowBounds的分页信息,进行逻辑分页(也就是在内存中分页)
skipRows(resultSet, rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
// 通过标签的子标签对结果映射进行鉴别
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 将查询结果封装到POJO中
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// 处理对象嵌套的映射关系
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
这段代码中简单的说下代码中的逻辑:
(1)、通过
public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix)
throws SQLException {
Set pastDiscriminators = new HashSet<>();
// 获取标签的子标签
Discriminator discriminator = resultMap.getDiscriminator();
while (discriminator != null) {
final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
if (configuration.hasResultMap(discriminatedMapId)) {
resultMap = configuration.getResultMap(discriminatedMapId);
Discriminator lastDiscriminator = discriminator;
discriminator = resultMap.getDiscriminator();
if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
break;
}
} else {
break;
}
}
return resultMap;
}
(2)、将查询结果封装到POJO中
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
// 延迟加载的映射信息
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建要映射的PO类对象
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
// 是否应用自动映射,也就是通过resultType进行映射
if (shouldApplyAutomaticMappings(resultMap, false)) {
// 根据columnName和type属性名映射赋值
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 根据我们配置ResultMap的column和property映射赋值
// 如果映射存在nestedQueryId,会调用getNestedQueryMappingValue方法获取返回值
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
(3)、处理对象嵌套的映射关系
private void storeObject(ResultHandler> resultHandler, DefaultResultContext resultContext,
Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
} else {
callResultHandler(resultHandler, resultContext, rowValue);
}
}
其实这个实现很简单,只是从一个集合里去除第一条数据而已:
private List collapseSingleResultList(List multipleResults) {
return multipleResults.size() == 1 ? (List) multipleResults.get(0) : multipleResults;
}
其实最后这这个结果集的映射实现是挺复杂的,不过由于篇幅原因,只能做一个简单的分析,当然这也是本系列的最后一篇文章了。但是我们还是来一个最后的总结吧。最后还是感谢大家的关注,后面笔者将会写其他系列的文章了,不过可能又会有大段时间的断更,因为笔者想好好闭关一下。