Mybatis笔记2-Handler

Handler

参数处理

Mybatis对接口实参的解析发生在创建Statement之前,对接口参数解析结果如下:

单个参数 : 直接将调用接口传入的实参返回,不需要进一步解析

多个参数:多个参数的情况下,会将参数转换成【参数名 -> 实参值】的映射关系Map
若接口形参使用了@Param参数,使用@Param参数指定的名称
若接口形参未使用@Param参数,JDK8以上可通过参数-parameters打开形参名称解析,未打开则解析结果为arg0、arg1...形式的【映射关系】
Mybatis还会为每个接口形参根据其位置生成一个兜底的param0、param1...形式的【映射关系】

ParamNameResolver类的功能是解析Mapper接口入参名称,解析参数的时机为:

public class MapperMethod {
    
    // ...

    private final SqlCommand command;   // 当前要操作的SQL标签,为在Mapper.xml文件中使用的<select><update><delete><insert>标签
    private final MethodSignature method; // 记录mapper接口命名标记信息
    
    public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        switch (command.getType()) {
            // ...
            case SELECT:
                // ...
                // 使用ParamNameResolver开始解析方法调用的【形参名->实参值】映射关系
                // 当方法仅有一个形参时,param即为方法传入实参
                // 当方法有多个形参是,param为Map类型,记录【形参名->实参值】映射关系
                Object param = method.convertArgsToSqlCommandParam(args);
                // 集成Spring时,当前的SqlSession对象为SqlTemplate类对象
                result = sqlSession.selectOne(command.getName(), param);
                break;
                // ...
            default:
                throw new BindingException("Unknown execution method for: " + command.getName());
        }
        // ...
        return result;
    }
}

解析接口名称类ParamNameResolver如下:

public class ParamNameResolver {
    
    private static final String GENERIC_NAME_PREFIX = "param";
    private final SortedMap<Integer, String> names;     // 记录解析得到的入参名称,映射关系为【参数位置 -> 参数名称】
    private boolean hasParamAnnotation;                 // 标记该方法是否使用了@Param注解
    
    // ...
    
    public ParamNameResolver(Configuration config, Method method) {
        // 获取接口参数类型数组
        final Class<?>[] paramTypes = method.getParameterTypes();
        // 获取接口每个参数的注解,由于参数前可以采用多个注解,因此使用二维数组
        final Annotation[][] paramAnnotations = method.getParameterAnnotations();
        final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
        // 记录方法参数个数,使用paramTypes数组长度也一样,如果没有被注解修饰的参数也会作为一个空数组放入这个二维数组
        int paramCount = paramAnnotations.length;
        // get names from @Param annotations
        for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
            // 若当前参数类型为RowBounds或者ResultHandler不处理
            if (isSpecialParameter(paramTypes[paramIndex])) {
                continue;
            }
            String name = null;
            // 遍历每一个参数的注解,查询是否使用了@Param注解,获取@Param上面的name属性
            for (Annotation annotation : paramAnnotations[paramIndex]) {
                if (annotation instanceof Param) {
                    hasParamAnnotation = true;
                    name = ((Param) annotation).value();
                    break;
                }
            }
            if (name == null) {
                if (config.isUseActualParamName()) {
                    // 将入参解析为arg0、arg1格式的名称
                    // jdk8(含)以上版本,可以在编译类的时候使用 -parameters 命令,那么就可以获取方法参数的名称
                    name = getActualParamName(method, paramIndex);
                }
                if (name == null) {
                    // 直接使用数字0,1,2作为入参名称
                    name = String.valueOf(map.size());
                }
            }
            map.put(paramIndex, name);
        }
        names = Collections.unmodifiableSortedMap(map);
    }
    
    /**
     * 解析接口参数名称
     * @param args 调用本接口的实参 
     * @return 使用Object类型返回,方法仅有一个形参时返回入参对象,有多个形参是,返回【形参名->实参值】映射关系Map对象
     **/
    public Object getNamedParams(Object[] args) {
        final int paramCount = names.size();
        // 如果调用接口实参为null 或 从接口上解析得到的参数个数为0
        if (args == null || paramCount == 0) {
            return null;
        } 
        // 如果没有使用@Param注解且参数就一个,直接返回传入的实参即可
        else if (!hasParamAnnotation && paramCount == 1) {  
            return args[names.firstKey()];
        } else {
            final Map<String, Object> param = new ParamMap<Object>();
            int i = 0;
            for (Map.Entry<Integer, String> entry : names.entrySet()) {
                // 保存参数名称 -> 实参值 映射关系
                param.put(entry.getValue(), args[entry.getKey()]);
                // 生成一个当前位置参数名称,格式为param1.....
                final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
                // 若不存在这个格式的参数名称,额外保存param1 -> 实参值 的映射关系
                if (!names.containsValue(genericParamName)) {
                    param.put(genericParamName, args[entry.getKey()]);
                }
                i++;
            }
            // 最终返回的一定有param1 -> 实参值的映射
            // 以下两种映射每个参数必存在一种
            // arg0 -> 实参
            // @Param注解定义名称 -> 实参
            return param;
        }
    }
}

StatementHandler

JDBC处理器,基于JDBC构建Statement并设置参数,然后执行SQL。每调用会话当中一次SQL,都会有与之相对应的且唯一的Statement实例。

image-20210507161009434

PreparedStatementHandler

相对来说,PreparedStatement的应用场景是所有Statement中应用最多的,这里以其对应的PreparedStatementHandler为例进行学习。

image-20210507161814048
创建PreparedStatement
public class SimpleExecutor extends BaseExecutor {
    
    // ...
    
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, 
                               ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        
        Configuration configuration = ms.getConfiguration();
        // 通过Configuration创建StatementHandler,然后由StatementHandler创建Statement
        // 这里以PreparedStatementHandler创建PreparedStatement为例
        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, 
                                                                     resultHandler, boundSql);
        // 拥有了PreparedStatementHandler之后,创建PreparedStatement
        Statement stmt = prepareStatement(handler, ms.getStatementLog());
        return handler.query(stmt, resultHandler);
    }
    
    // 通过PreparedStatementHandler之后,创建PreparedStatement
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        Connection connection = getConnection(statementLog);
        // 通过BaseStatementHandler创建PreparedStatement
        stmt = handler.prepare(connection, transaction.getTimeout());
        // 为PreparedStatement的占位符?设置参数
        handler.parameterize(stmt);
        return stmt;
    }
}

// 展示SimpleExecutor类中通过Configuration创建PreparedStatement的相关方法
public class Configuration {
    
    // ...
    
    // 通过Configuration创建StatementHandler
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, 
                                                Object parameterObject, RowBounds rowBounds, 
                                                ResultHandler resultHandler, BoundSql boundSql) {
        
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, 
                                                                        rowBounds, resultHandler, boundSql);
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
    }
    
}

// Configuration通过RoutingStatementHandler创建不同种类的StatementHandler,主要根据MappedStatement配置属性StatementType决定
public class RoutingStatementHandler implements StatementHandler {
    
    private final StatementHandler delegate;
    
    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, 
                                   ResultHandler resultHandler, BoundSql boundSql) {
        // 根据MappedStatement的配置信息,选择创建不同的Statement
        switch (ms.getStatementType()) {
            case STATEMENT:
                delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            case PREPARED:
                delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            case CALLABLE:
                delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                break;
            default:
                throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
        }
    }
    
    // ...
}

// PreparedStatementHandler创建PreparedStatement对象,通过调用父类BaseStatementHandler抽取的共同方法prepare实现
public abstract class BaseStatementHandler implements StatementHandler {
    
    // 创建Statement对象
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
            // instantiateStatement是个抽象方法,由子类StatementHandler、PreparedStatementHandler、CallableStatementHandler实现
            statement = instantiateStatement(connection);
            setStatementTimeout(statement, transactionTimeout);
            setFetchSize(statement);
            return statement;
        } catch (SQLException e) {
            // ...
        } catch (Exception e) {
            // ...
        }
    }
    
}


public class PreparedStatementHandler extends BaseStatementHandler {
    
    // ...
    
    // 实现父类BaseStatementHandler中的抽象方法instantiateStatement,创建PreparedStatement
    protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = boundSql.getSql();
        if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
            String[] keyColumnNames = mappedStatement.getKeyColumns();
            if (keyColumnNames == null) {
                return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
            } else {
                return connection.prepareStatement(sql, keyColumnNames);
            }
        } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
            return connection.prepareStatement(sql);
        } else {
            return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
        }
    }
}

ParameterHandler

通过TypeHandler为PreparedStatement设置参数
public class ReuseExecutor extends BaseExecutor {

    // ...
    
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        Connection connection = getConnection(statementLog);
        stmt = handler.prepare(connection, transaction.getTimeout());
        // 创建好PreparedStatement之后,为其设置参数
        handler.parameterize(stmt);
        return stmt;
    }

}

public class PreparedStatementHandler extends BaseStatementHandler {
 
    // ...
    
    public void parameterize(Statement statement) throws SQLException {
        parameterHandler.setParameters((PreparedStatement) statement);
    }
}

// 设置参数处理器,有且仅有此实现
public class DefaultParameterHandler implements ParameterHandler {
    
    // ...
    
    public void setParameters(PreparedStatement ps) {
        // 得到Sql的相关参数信息,内含TypeHandler,JdbcType,JavaType
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                // 不是存储过程的OUT参数
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) { 
                        value = boundSql.getAdditionalParameter(propertyName);
                    } 
                    // Mapper接口没有形参,也就没有实参,直接将要设置的value值赋值为null
                    else if (parameterObject == null) {
                        value = null;
                    } 
                    // 检查是否有TypeHandler可以处理当前接口实参类型,符合这个方法的话表示当前接口方法仅有一个形参且为基本类型,
                    // 否则parameterObject为Map类型
                    // TypeHandlerRegistry记录了 JavaType -> JdbcType -> TypeHandler 的映射关系,
                    // 存在 JavaType -> null -> TypeHandler 的映射关系,表示该java类型没有指定jdbc类型默认使用的TypeHandler
                    else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        // TODO 这个metaObject对象为什么不直接作为本方法的全局变量????
                        // TODO 如果parameterObject为Map<String,Object>类型、非简单类型,不是每次都需要重新解析???
                        
                        // MetaObject可以通过反射获取Map<String,Object>以及用户自定义对象属性的值
                        MetaObject metaObject = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    TypeHandler typeHandler = parameterMapping.getTypeHandler();
                    JdbcType jdbcType = parameterMapping.getJdbcType();
                    if (value == null && jdbcType == null) {
                        jdbcType = configuration.getJdbcTypeForNull();
                    }
                    try {
                        // 通过TypeHandler为PreparedStatement设置占位符实参
                        typeHandler.setParameter(ps, i + 1, value, jdbcType);
                    } catch (TypeException | SQLException e) {
                        // ...
                    }
                }
            }
        }
    }
}

ResultSetHandler

执行数据库查询,处理返回的结果集

public class SimpleExecutor extends BaseExecutor {
    
    // ...
    
    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, 
                               ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, 
                                                                         resultHandler, boundSql);
            stmt = prepareStatement(handler, ms.getStatementLog());
            // 通过PreparedStatementHandler执行数据库查询操作
            return handler.query(stmt, resultHandler);
        } finally {
            // 关闭PreparedStatement
            closeStatement(stmt);
        }
    }
}

// 通过PreparedStatementHandler触发数据库操作
public class PreparedStatementHandler extends BaseStatementHandler {

    // ...
    
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        // 调用JDBC的PreparedStatement#execute执行数据库操作
        ps.execute();
        // 使用ResultSetHandler处理返回的结果集ResultSet
        return resultSetHandler.handleResultSets(ps);
    }
}

// 使用ResultSetHandler处理返回结果集ResultSet
public class DefaultResultSetHandler implements ResultSetHandler {
 
    // ...
    
    public List<Object> handleResultSets(Statement stmt) throws SQLException {
        
        final List<Object> multipleResults = new ArrayList<>();
        
        int resultSetCount = 0;
        // 获取第一个结果集,由于存储过程可能有多个出参,存在多个结果集返回的情况
        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++;
        }
        // ...
        // 由于存在存储过程有多个结果集的情况,multipleResults可能是List<List<Object>>集合嵌套集合类型,
        // 如果仅仅一个结果集的处理结果,直接返回第一个元素List<Object>结果即可
        return collapseSingleResultList(multipleResults);
    }
    
    // 处理结果集
    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) {
                    // 使用ResultHandler(注意区分ResultSetHandler)解析好的结果
                    // DefaultResultHandler在下文有源码展示,其实就是简单的使用了一个List集合保存解析的每一行结果集结果
                    DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
                    // 开始处理结果集的每一行数据(下有源码细节)
                    handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
                    // 从ResultHandler保存的结果List中获取数据,放入multipleResults集合作为参数返回
                    multipleResults.add(defaultResultHandler.getResultList());
                } else {
                    handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
                }
            }
        } finally {
            // 关闭ResultSet结果集
            closeResultSet(rsw.getResultSet());
        }
    }
    
    // 开始将ResultSet结果集的每一行处理为对    象返回
    public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, 
                                RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        // 判断当前方法的ResultMap是否嵌套了另一个ResultMap,比如:
        /* <resultMap id="resultMap" type="doman实体" extends="BaseResultMap">
               <collection property="c" resultMap="otherBaseResultMap"/>
           </resultMap>
         */
        if (resultMap.hasNestedResultMaps()) {
            ensureNoRowBounds();
            checkResultHandler();
            handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        } else {
            // 暂时不去探究嵌套ResultMap处理,先来看单个ResultMap如何处理的(下有源码细节)
            handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        }
    }
    
    // 针对单一ResultMap的情况进行结果集解析
    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, 
                                                   ResultHandler<?> resultHandler, RowBounds rowBounds, 
                                                   ResultMapping parentMapping) throws SQLException {
        
        // ResultContext类可以看做是解析ResultSet过程的一个上下文对象,用来记录当前最新解析结果集行结果,记录解析行数,是否达到分页条目停止解析
        DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
        // 分页查询时,将结果集偏移量调整到分页开始行
        skipRows(rsw.getResultSet(), rowBounds);
        // 条件1 : 通过ResultContext当前是否设置了停止解析 或 到达分页条目  不再进一步解析结果集(下有源码细节)
        // 条件2 : 结果集不再有下一行
        while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
            ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
            // rowValue表示一个解析成ResultMap指定类型的一行结果集数据(下有源码细节)
            Object rowValue = getRowValue(rsw, discriminatedResultMap);
            // 将这一行结果集处理的结果保存到ResultHandler和ResultContext(下有源码细节)
            storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
        }
    }
    
    // 通过ResultContext和RowBounds判断是否需要继续解析结果集ResultSet
    private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) throws SQLException {
        return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
    }
    
    // 存储解析得到的一行ResultSet结果
    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);
        }
    }
    
    // 存储ResultSet每一行处理结果
    private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, 
                                   Object rowValue) {
        // ResultContext保存每一次最后解析得到的对象,并记录解析过多少行
        resultContext.nextResultObject(rowValue);
        // 将每一行ResultSet结果处理结果存放到ResultHandler的属性集合中(该类下有DefaultResultHandler实现源码细节)
        ((ResultHandler<Object>) resultHandler).handleResult(resultContext);
    }
    
    // 解析结果集ResultSet一行数据,封装成目标类型返回
    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())) {
            final MetaObject metaObject = configuration.newMetaObject(rowValue);
            boolean foundValues = this.useConstructorMappings;
            // <rusultMap id="ddd" type="user" autoMapping="true">,可以通过如上方法,指定ResultMap采用自动映射机制
            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;
    }
    
    // 创建ResultMap指定的返回对象类型
    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, 
                                      String columnPrefix) throws SQLException {
        this.useConstructorMappings = false; 
        final List<Class<?>> constructorArgTypes = new ArrayList<Class<?>>();
        final List<Object> constructorArgs = new ArrayList<Object>();
        // 具体创建返回对象方法(下有源码细节)
        /*
            ResultMap标签可以指定创建返回类的构造器,如下:
            <resultMap id="RoleResultMap" type="RoleDTO">
                <constructor>
                    <arg column="user_id"/>
                </constructor>
            </resultMap>
        */
        Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
        
        if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
            final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
            for (ResultMapping propertyMapping : propertyMappings) {
                // 嵌套查询为如下情况:
                /* <resultMap id="ddd" type="user">
                        <asoociation property="author" select="selectByUserId">
                   </resultMap>
                 */
                if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
                    resultObject = configuration.getProxyFactory().createProxy(resultObject, 
                                                                               lazyLoader, configuration, objectFactory, 
                                                                               constructorArgTypes, constructorArgs);
                    break;
                }
            }
        }
        this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty();
        return resultObject;
    }
    
    // 根据ResultMap创建每一行返回的空对象
    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, 
                                      List<Object> constructorArgs, String columnPrefix) throws SQLException {
        // 获取ResultMap的返回类型
        final Class<?> resultType = resultMap.getType();
        // 解析返回类型的元数据信息
        final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
        final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
        // 如果是原始类型,直接使用TypeHandler处理数据返回
        if (hasTypeHandlerForResultObject(rsw, resultType)) {
            return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
        } 
        // 如果ResultMap存在构造器映射配置,则通过构造器创建
        else if (!constructorMappings.isEmpty()) {
            return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, 
                                                   constructorArgs, columnPrefix);
        } 
        // 如果返回类型是个接口,或者存在默认构造器,直接创建一个空对象
        else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
            return objectFactory.create(resultType);
        } 
        // 基于自动映射,自动一依次查找是否于指定构造方法匹配,若有自动创建对象
        else if (shouldApplyAutomaticMappings(resultMap, false)) {
            return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
        }
        throw new ExecutorException("Do not know how to create an instance of " + resultType);
    }
    
    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();
        // TODO 只要有一个属性填充上就表示可以返回该对象?????????
        for (ResultMapping propertyMapping : propertyMappings) {
            String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
            if (propertyMapping.getNestedResultMapId() != null) {
                column = null;
            }
            if (propertyMapping.isCompositeResult()
                    || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
                    || propertyMapping.getResultSet() != null) {
                // 存在嵌套子查询的处理
                Object value = 
                    getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, 
                                                       lazyLoader, columnPrefix);
                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())) {
                    metaObject.setValue(property, value);
                }
            }
        }
        return foundValues;
    }
    
    private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, 
                                           ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
        /* <resultMap id="ddd" type="user">
                <asoociation property="author" select="selectByUserId">
           </resultMap>
        */
        if (propertyMapping.getNestedQueryId() != null) {
            return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
        } 
         /* <resultMap id="ddd" type="user">
                <asoociation property="author" resultSet="ss" select="selectByUserId">
           </resultMap>
        */
        else if (propertyMapping.getResultSet() != null) {
            addPendingChildRelation(rs, metaResultObject, propertyMapping);   // TODO is that OK?
            return DEFERED;
        } else {
            final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
            final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
            return typeHandler.getResult(rs, column);
        }
    }
}

补充:使用ResultContext控制解析结果集数量例子

ResultHandler范例

ResultHandler

使用一个list保存解析ResultSet每一行的结果

public class DefaultResultHandler implements ResultHandler<Object> {
    private final List<Object> list;
    
    public DefaultResultHandler() {
        list = new ArrayList<Object>();
    }
    
    public DefaultResultHandler(ObjectFactory objectFactory) {
        list = objectFactory.create(List.class);
    }
    
    @Override
    public void handleResult(ResultContext<? extends Object> context) {
        list.add(context.getResultObject());
    }
    
    public List<Object> getResultList() {
        return list;
    }
}

附录

MapperMethod与SqlSessionTemplate的关系

Mybatis集成Spring后,通过向Spring注册MapperFactoryBean生产Mapper接口的代理对象,每个代理对象都会持有SqlSessionTemplate对象,当程序触发代理对象的方法时,JDK动态代理拦截方法调用,会通过MepperMethod#execute调用SqlSessionTemplate方法,而SqlSessionTemplate又会将查询委托给自己封装的另一个代理sqlSessionProxy。

image-20210507220144214
public class MapperProxyFactory<T> {
    
    // ...
    
    // 要生成代理对的接口
    private final Class<T> mapperInterface;
    // 
    private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
    
    
    // 生成Mapper接口的代理对象
    protected T newInstance(MapperProxy<T> mapperProxy) {
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
    }
    
    public T newInstance(SqlSession sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
    }

}

public class MapperProxy<T> implements InvocationHandler, Serializable {

    // ...
    
    private final SqlSession sqlSession;    // 集成Mybatis,该属性注入SqlSessionTemplate对象
    
    // 调用Mapper接口代理对象方法,会被该方法拦截
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            } else if (isDefaultMethod(method)) {
                return invokeDefaultMethod(proxy, method, args);
            }
        } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
        }
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        return mapperMethod.execute(sqlSession, args);
    }
}
public class SqlSessionTemplate implements SqlSession, DisposableBean {
    private final SqlSessionFactory sqlSessionFactory;
    private final ExecutorType executorType;
    private final SqlSession sqlSessionProxy;
    private final PersistenceExceptionTranslator exceptionTranslator;
    
    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
                              PersistenceExceptionTranslator exceptionTranslator) {
        
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        // 创建代理对象
        this.sqlSessionProxy = (SqlSession) newProxyInstance(
            SqlSessionFactory.class.getClassLoader(),
            new Class[] { SqlSession.class },
            new SqlSessionInterceptor());
    }
    
    // SqlSessionTemplate内部的方法都委托给另一个代理对象sqlSessionProxy
    public <T> T selectOne(String statement, Object parameter) {
        return this.sqlSessionProxy.<T> selectOne(statement, parameter);
    }
    
    // ... 
}

查询流程图

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容