This is the 29th day of my participation in the August Wenwen Challenge.More challenges in August

Sequence diagram

sequenceDiagram
participant C as SimpleExecutor
participant A as PreparedStatementHandler
participant B as DefaultResultSetHandler

C ->> A : query
A ->> B : handleResultSets
B ->> B : handleResultSet
B ->> B : handleRowValues
B ->> B : handleRowValuesForSimpleResultMap
B ->> B : getRowValue
B ->> B : applyPropertyMappings
B -->> C : List<Object>

The detailed steps

PreparedStatementHandler#query

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    / / SQL execution
    ps.execute();
    // Result set processing
    return resultSetHandler.handleResultSets(ps);
}
Copy the code

DefaultResultSetHandler#handleResultSets

/** * Process multiple result sets (or single result sets, which is a simplified form of multiple result sets) resulting in a list of results ** The handleResultSets method completes processing of multiple result sets. But processing for each result set is implemented by the handleResultSet submethod *@paramSTMT Statement *@returnResult list@throws SQLException
 */
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

    // A list of processing results to store
    final List<Object> multipleResults = new ArrayList<>();

    // There may be multiple result sets. This variable is used to count the result sets
    int resultSetCount = 0;
    // There may be multiple result sets, so first fetch the first result set
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    // There may be multiple resultMap nodes corresponding to the query statement
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    // Verify validity (resultMapCount cannot be 0 if there is output result set)
    validateResultMapsCount(rsw, resultMapCount);
    // Loop through each result set with a resultMap set
    while(rsw ! =null && resultMapCount > resultSetCount) {
        // Get the ResultMap of the current result set
        ResultMap resultMap = resultMaps.get(resultSetCount);
        // Perform result set processing
        handleResultSet(rsw, resultMap, multipleResults, null);
        // Get the next result set
        rsw = getNextResultSet(stmt);
        // Clean up the environment of the previous result set
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
    }

    // Get the names of all the result sets in the multi-result set
    String[] resultSets = mappedStatement.getResultSets();
    if(resultSets ! =null) {
        // Loop through each resultMap set
        while(rsw ! =null && resultSetCount < resultSets.length) {
            // Obtain the resultMapping in the parent resultMap of the result set (note: The resultMapping is used to describe the mapping relationship of object attributes)
            ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
            if(parentMapping ! =null) {
                // Get the nested resultMap number
                String nestedResultMapId = parentMapping.getNestedResultMapId();
                ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
                // Handle nested mappings
                handleResultSet(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; }}// Determine if there is a single result set: if so, return the result list; If not, return a list of result sets
    return collapseSingleResultList(multipleResults);
}
Copy the code

DefaultResultSetHandler#handleResultSet

/** * handles a single result set *@paramRSW ResultSet packaging *@paramResultMap Indicates the resultMap node information *@paramMultipleResults are a list of processed results@param parentMapping
 * @throws SQLException
 */
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
        if(parentMapping ! =null) { // The nested result
            // Break parentMapping into submethods. Process records in the results
            handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
        } else { // Non-nested result
            if (resultHandler == null) {
                // defaultResultHandler returns the result object as a list of aggregated objects
                DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
                // Process the record in the result
                handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
                // Add the result after processing
                multipleResults.add(defaultResultHandler.getResultList());
            } else {
                handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); }}}finally {
        // issue #228 (close resultsets)closeResultSet(rsw.getResultSet()); }}Copy the code

DefaultResultSetHandler#handleRowValuesForSimpleResultMap

/** * The result of processing non-nested mappings *@paramRSW result set packaging *@paramResultMap Indicates the result mapping *@paramResultHandler resultHandler *@paramRowBounds Page turn restrictions *@paramParentMapping Parent result mapping *@throws SQLException
 */
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler
        resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
        throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    // The current result set to process
    ResultSet resultSet = rsw.getResultSet();
    // Skip the specified line according to the paging configuration
    skipRows(resultSet, rowBounds);
    // continue processing the next result, the judgment condition is; There's still a result to deal with and the result set is not closed and then there's the next result
    while(shouldProcessMoreRows(resultContext, rowBounds) && ! resultSet.isClosed() && resultSet.next()) {// resultMap is used after discriminator analysis
        ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
        // Take a row of records and convert it to an object
        Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
        // Save the converted objectstoreObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); }}Copy the code

DefaultResultSetHandler#getRowValue

  • When parsing ResultMap tags, the attribute TypeHandler will be determined, see Mybatis source code ResultMap tag parsing
/** * Convert a record to an object *@paramRSW result set packaging *@paramResultMap Indicates the result mapping *@paramColumnPrefix columnPrefix *@returnThe converted object *@throws SQLException
 */
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    // Create an empty object for this row
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if(rowValue ! =null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        // Get the MetaObject from the object
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        boolean foundValues = this.useConstructorMappings;
        // Whether to allow automatic mapping of unstated fields
        if (shouldApplyAutomaticMappings(resultMap, false)) {
            // Automatically map an unspecified field (resultType). The Mapping TypeHandler obtains the attribute type by mapping the attribute name to the parameter type of the set method, and obtains the corresponding TypeHandler accordingly
            foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        // Remap according to explicit fields (resultMap), retrieve TypeHandler when parsing XML
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
}
Copy the code

The above is the processing process of ResultSet in Mybatis.