mybatis源碼學習及分析之執行過程分析——返回結果的處理
上一篇中分析了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。