MyBatis源码学习三之查询主逻辑

news2024/12/24 8:24:34

MyBatis源码学习三之查询主逻辑

继续上一章节。

MyBatis的一个主要流程图。从图中可以看出,核心的东西主要集中在3个Handler中。分别是入参处理,执行sql语句处理,以及返回结果处理。

在这里插入图片描述

一 实例

Test

public static void main(String[] args) {
    InputStream inputStream = null;
    try {
        inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.getUserById("20");
        System.err.println(user.getId() + " : " + user.getUserName());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

UserMapper

public interface UserMapper {

    @Select("select name from user where id=#{id}")
    User getUserById(@Param String id);
}

上一节,我们看到MapperProxy.invokeMapperMethod.execute那我们就接着进入这里来看。

MapperMethod.execute

这里的command.getType是select。而且是一个单结果集的返回,就会进入到case select中最后一个else中。

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
        case INSERT: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
        }
        case UPDATE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
        }
        case DELETE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
        }
        case SELECT:
            if (method.returnsVoid() && method.hasResultHandler()) {
                executeWithResultHandler(sqlSession, args);
                result = null;
            } else if (method.returnsMany()) {
                result = executeForMany(sqlSession, args);
            } else if (method.returnsMap()) {
                result = executeForMap(sqlSession, args);
            } else if (method.returnsCursor()) {
                result = executeForCursor(sqlSession, args);
            } else {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(command.getName(), param);
                if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) {
                    result = Optional.ofNullable(result);
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
        throw new BindingException("Mapper method '" + command.getName()
                                   + "' attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
}

二 参数处理

MethodSignature.convertArgsToSqlCommandParam

public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
    Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
    if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
    } else if (resolvedReturnType instanceof ParameterizedType) {
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
    } else {
        this.returnType = method.getReturnType();
    }
    this.returnsVoid = void.class.equals(this.returnType);
    this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
    this.returnsCursor = Cursor.class.equals(this.returnType);
    this.returnsOptional = Optional.class.equals(this.returnType);
    this.mapKey = getMapKey(method);
    this.returnsMap = this.mapKey != null;
    this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
    this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
    this.paramNameResolver = new ParamNameResolver(configuration, method);
}

public Object convertArgsToSqlCommandParam(Object[] args) {
    return paramNameResolver.getNamedParams(args);
}

ParamNameResolver.getNamedParams

public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
    if (args == null || paramCount == 0) {
        return null;
    }
    // 没有@Param注解,并且参数只有一个,符合这个条件
    if (!hasParamAnnotation && paramCount == 1) {
		// 把实际传入的value值赋值给参数
        Object value = args[names.firstKey()];
        // 进行了类型包装,只有当类型是Collection和Array才生效。
        return wrapToMapIfCollection(value, useActualParamName ? names.get(names.firstKey()) : null);
    } else {
        final Map<String, Object> param = new ParamMap<>();
        int i = 0;
        for (Map.Entry<Integer, String> entry : names.entrySet()) {
            param.put(entry.getValue(), args[entry.getKey()]);
            // add generic param names (param1, param2, ...)
            final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
            // ensure not to overwrite parameter named with @Param
            if (!names.containsValue(genericParamName)) {
                param.put(genericParamName, args[entry.getKey()]);
            }
            i++;
        }
        return param;
    }
}
public static Object wrapToMapIfCollection(Object object, String actualParamName) {
    if (object instanceof Collection) {
        ParamMap<Object> map = new ParamMap<>();
        map.put("collection", object);
        if (object instanceof List) {
            map.put("list", object);
        }
        Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
        return map;
    }
    if (object != null && object.getClass().isArray()) {
        ParamMap<Object> map = new ParamMap<>();
        map.put("array", object);
        Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
        return map;
    }
    return object;
}

这里完了后,再次回到MapperMethod.execute中,继续往下走到sqlSession.selectOne

DefaultSqlSession.selectOne

多次重载后,进入到private的selectList方法中。从configuration中拿取了 MapperStatement,然后调用executor.query

而这个executor有2个实现类,分别是BaseExecutorCacheExecutor。而CacheExecutor是做二级缓存的,我们不开启二级缓存,那么就进入到BaseExecutor中。

@Override
public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.selectList(statement, parameter);
    if (list.size() == 1) {
        return list.get(0);
    }
    if (list.size() > 1) {
        throw new TooManyResultsException(
            "Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
        return null;
    }
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
}

private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
    try {
        MappedStatement ms = configuration.getMappedStatement(statement);
        dirty |= ms.isDirtySelect();
        return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

BaseExecutor.query

获取到原生的sql语句以及参数的映射,然后再创建一个用作缓存的key值,这个值的创建考虑的因素比较多。这里就不介绍了。

然后再继续调用query方法。

@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)
    throws SQLException {
    // 获取到原生的sql语句以及参数的映射
    BoundSql boundSql = ms.getBoundSql(parameter);
    // 创建一个缓存的key
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    // mimic DefaultParameterHandler logic
    for (ParameterMapping parameterMapping : parameterMappings) {
        if (parameterMapping.getMode() != ParameterMode.OUT) {
            Object value;
            String propertyName = parameterMapping.getProperty();
            if (boundSql.hasAdditionalParameter(propertyName)) {
                value = boundSql.getAdditionalParameter(propertyName);
            } else if (parameterObject == null) {
                value = null;
            } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                value = parameterObject;
            } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                value = metaObject.getValue(propertyName);
            }
            cacheKey.update(value);
        }
    }
    if (configuration.getEnvironment() != null) {
        // issue #176
        cacheKey.update(configuration.getEnvironment().getId());
    }
    return cacheKey;
}

@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
                         CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    List<E> list;
    try {
        queryStack++;
        // localCache中没有存放任何东西,所以这里的list也是null,进入查询数据库的语句中
        list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
        if (list != null) {
            handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
        } else {
            list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    } finally {
        queryStack--;
    }
    if (queryStack == 0) {
        for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
        }
        // issue #601
        deferredLoads.clear();
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            // issue #482
            clearLocalCache();
        }
    }
    return list;
}

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds,
                                      ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
        list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
        localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
        localOutputParameterCache.putObject(key, parameter);
    }
    return list;
}
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
                                       ResultHandler resultHandler, BoundSql boundSql) throws SQLException;

再进入到doQuery方法。而这个doQuery是一个抽象的方法。那么只能看看实现类了。

在这里插入图片描述

而在初始化的时候,我们没有指定Executor的类型,那么这个类型就是默认的SimpleExecutor

SimpleExecutor.doQuery

现获取到configuration对象,再去创建StatementHandler对象。

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());
        return handler.query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}

Configuration.newStatementHandler

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement,
                                            Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // 实例化statementHandler
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject,
                                                                    rowBounds, resultHandler, boundSql);
    // 用插件进行装饰
    return (StatementHandler) interceptorChain.pluginAll(statementHandler);
}

RoutingStatementHandler

ms的statementType默认是PREPARED

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
                               ResultHandler resultHandler, BoundSql boundSql) {
    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

public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter,
                                RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}

BaseStatementHandler

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject,
                               RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
        generateKeys(parameterObject);
        boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;
	// 实例化另外2个插件修饰的对象
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler,
                                                              resultHandler, boundSql);
}

Configuration

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,
                                            BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement,
                                                                                         parameterObject, boundSql);
    return (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
}

public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds,
                                            ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,
                                                                    resultHandler, boundSql, rowBounds);
    return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
}

这里初始化就完成了,开始调用真正的query。

PreparedStatementHandler.query

调用jdbc中ps的execute方法。resultSetHandler刚才已经实例过,直接调用

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.handleResultSets(ps);
}

DefaultResultHandler.handleResultSets

public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    final List<Object> multipleResults = new ArrayList<>();
    int resultSetCount = 0;
    // 获取ResutlSet的包装类
    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 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还未实例化,进入到这里
            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<Object> resultContext = new DefaultResultContext<>();
    ResultSet resultSet = rsw.getResultSet();
    // 跳过逻辑分页
    skipRows(resultSet, rowBounds);
    while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
        ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
        //  对对象进行赋值
        Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
        storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
    }
}

private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
    if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
        if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
            rs.absolute(rowBounds.getOffset());
        }
    } else {
        for (int i = 0; i < rowBounds.getOffset(); i++) {
            if (!rs.next()) {
                break;
            }
        }
    }
}

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    // 实例化返回的对象,也就是User类 
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        boolean foundValues = this.useConstructorMappings;
        // 需要自动映射对象,也就是id对应字段User中的id
        if (shouldApplyAutomaticMappings(resultMap, false)) {
            foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
}

// 实例化返回的对象,也就是User类,这里一定用的是反射
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader,
                                  String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();
    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) {
            // issue gcode #109 && issue #149
            if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
                resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration,
                                                                           objectFactory, constructorArgTypes, constructorArgs);
                break;
            }
        }
    }
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
    return resultObject;
}
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,
                                  List<Object> constructorArgs, String columnPrefix) throws SQLException {
    final Class<?> resultType = resultMap.getType();
    // 反射类
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
        return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    }
    if (!constructorMappings.isEmpty()) {
        return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs,
                                               columnPrefix);
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
        // 最终使用objectFactory.create了User对象出来了 
        return objectFactory.create(resultType);
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
        return createByConstructorSignature(rsw, resultMap, columnPrefix, resultType, constructorArgTypes,
                                            constructorArgs);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
}

private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
                                       String columnPrefix) throws SQLException {
    List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    if (!autoMapping.isEmpty()) {
        for (UnMappedColumnAutoMapping mapping : autoMapping) {
            final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
            if (value != null) {
                foundValues = true;
            }
            if (value != null || configuration.isCallSettersOnNulls() && !mapping.primitive) {
                // gcode issue #377, call setter on nulls (value is not 'found')
                // 通过反射一步步的把数据set进去
                metaObject.setValue(mapping.property, value);
            }
        }
    }
    return foundValues;
}

到这里再把结果封装一下,然后再返回给List对象,就完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/568362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Revit建模|10种方法帮你解决Revit操作卡顿!

大家好&#xff0c;这里是建模助手。 相信各位BIMer在使用Revit建模时&#xff0c;肯定遇到过软件加载慢或者程序未响应的现象。我们经过测试发现&#xff0c;除了硬件配置及软件本身的问题以外&#xff0c;建模习惯及软件使用方法不当也会造成软件卡顿。 以下就是我们总结的…

TPlinker解读

参考&#xff1a; 关系抽取之TPLinker解读加源码分析 TPLinker 实体关系抽取代码解读 实体关系联合抽取&#xff1a;TPlinker TPLinker中文注释版 Tagging TPLinker模型需要对关系三元组(subject, relation, object)进行手动Tagging&#xff0c;过程分为三部分&#xff1a; &…

阿里面试,HR说我不配21K,直接翻脸.....

好家伙&#xff0c;这奇葩事可真是多&#xff0c;前两天和粉丝聊天&#xff0c;他说前段时间面试阿里的测开岗&#xff0c;最后和面试官干起来了。 我问他为什么&#xff0c;他说没啥&#xff0c;就觉得面试官太装了&#xff0c;我说要21K&#xff0c;他说太高了&#xff0c;说…

【全国产龙芯平台】迅为iTOP-LS3A5000_7A2000开发板+银河麒麟操作系统

硬件准备 1.M.2.ssd硬盘&#xff08;最好大于等于128G&#xff09;&#xff1b; 2.迅为LS3A5000开发板&#xff1b; 3.U盘&#xff08;需大于8g&#xff09;&#xff0c;制作启动盘使用&#xff1b; 4.hdmi显示器&#xff1b; 5.搭载linux环境的计算机。 安装步骤 1 制作…

【多线程】两阶段终止模式

目录 一、两阶段终止模式说明二、错误思路三、实现思路图四、实现思路五、方法说明六、interrupt实现6.1 代码示例6.2 示例截图 七、volatile实现7.1 代码示例7.2 示例截图 一、两阶段终止模式说明 1.在一个线程t1中优雅地终止另一个线程t2&#xff0c;指终止t2线程前&#xff…

【C++】位图/布隆过滤器+海量数据处理

✍作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;C 文章目录 前言一 位图1.位图法介绍2.位图实现的细节 二、布隆过滤器1.布隆过滤器概念2.布隆过滤器实现 三、海量数据处理1. 位图应用2. 哈希切割3. 布隆过滤器 前言 题目 给40亿个不重复的无符号整数&#xff0c;没…

Java

FileOutputStream写数据的3种方式 void write(int b) //一次写一个字节的数据 void write(byte[] b) //一次写一个字节数组数据 void write(byte[] b, int off,int len) //一次写一个字节数组的部分数据 参数一:数组;参数二:起始索引 0;参数三:个数换行: windows:“\r\n” lin…

springboot+java小区社区宽带安装管理系统

本次程序软件的开发的目的就是让使用者可以通过使用该软件提高信息数据的管理效率&#xff0c;同时该程序软件也需要针对不同的操作用户设置对应的功能&#xff0c;因此&#xff0c;此程序的操作流程应该尽量与用户日常操作软件的行为习惯相贴合&#xff0c;另外&#xff0c;程…

分享最强国内免费ChatGPT的镜像网站,记得收藏(2023年更新中)

众所周知的原因&#xff0c;要想在国内使用ChatGPT&#xff0c;肯定是要“折腾一番”的。但是对于绝大多数普通小白&#xff0c;有没有比较容易的方法就用上官方的ChatGPT呢&#xff1f;答案是肯定的&#xff0c;下面就给大家分享几个2023年我正在使用的ChatGPT镜像网址&#x…

Python入门学习

一、执行Python&#xff08;Hello World&#xff09;程序 对于大多数程序语言&#xff0c;第一个入门编程代码便是 “Hello World&#xff01;”&#xff0c;以下代码为使用 Python 输出 “Hello World&#xff01;” 1.1 创建hello.py文件 1.2 编写程序 #!/usr/bin/python…

听我一句劝,别去外包,干了五年,废了....

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入杭州某软件公司&#xff0c;干了接近5年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了5年的功能测试…

Gateway网关参数进行验签POST 包含requestbody 请求体封装

Gateway网关自定义拦截器的不可重复读取数据 特别注意一点, 因为在网关层 拿出 request 流之后,必须重写getbody()方法把所有的参数放进去,否则后面转发的请求无法接收到任何数据, 坑,巨坑,因为版本问题网上很多都不能兼容, 我的springboot环境 依赖包 <parent><gr…

Linux--ServerProgramming--TCP\IP协议族

1.TCP/IP 协议族 1.1 TCP/IP协议族及主要协议 TCP/IP 协议族是一个四层协议系统。自上而下为&#xff08;如下图所示&#xff09;&#xff1a;应用层传输层网络层数据链路层 应用层负责处理应用程序逻辑&#xff0c;在用户空间实现。&#xff08;少数服务器程序在内核中实现。…

如何下载外文期刊文献,怎么下载又快又省力!

文章开头我们先了解一下下面这些查找外文期刊文献的数据库: 1、Web of Science&#xff1a;是获取全球学术信息的重要数据库。它收录了全球13000多种权威的、高影响力的学术期刊&#xff0c;内容涵盖自然科学、工程技术、生物医学、社会科学、艺术与人文等领域。其中以SCIE、S…

OpenCV入门简单的人脸识别项目

在学会图像处理和打开摄像头获取视频流后&#xff0c;就可以开展简单的人脸识别项目。 文章目录 检测人脸区域并绘制矩形多个人脸进行识别绘制五官位置视频检测人脸人脸识别 人脸识别首先需要检测到人脸。 检测人脸区域并绘制矩形 # 加载图片img face_recognition.load_image…

接口全生命周期的生产利器 ApiKit

一、ApiKit 整体介绍&#xff1a; 1、接口管理的需求与现状&#xff1a; 在软件项目研发的过程中&#xff0c;必然存在以下几个需求&#xff1a; API 接口文档的管理&#xff0c;常用的解决方案有 Swagger API 接口的调试&#xff0c;常用的解决方案有 Postman API 接口的自…

Java——网络编程套接字

目录 一、网络编程基础 1.1 为什么需要网络编程&#xff1f;——丰富的网络资源 二、什么是网络编程? 三、网络编程中的基本概念 3.2 请求和响应 3.3 客户端和服务端 常见的客户端服务端模型 四、Socket套接字 五、通信模型 5.1 Java数据报套接字通信模型 5.2 Java流…

【大数据之Hive】二、Hive安装

Hive安装部署&#xff08;最小化部署&#xff09; 安装部署Hive&#xff08;最小化只用于本机测试环境中&#xff0c;不可用于生产环境&#xff09;&#xff0c;并运行。 步骤&#xff1a; &#xff08;1&#xff09;把apache-hive-3.1.3-bin.tar.gz解压到/opt/module/目录下&…

IIC总线学习

IIC总线 1.总线空闲状态。2.IIC总线的起始停止条件。3.IIC总线的数据传送4.IIC总线的应答5.IIC时序 1.总线空闲状态。 总线空闲时&#xff0c;SDA和SCL均为高电平。 2.IIC总线的起始停止条件。 起始条件&#xff1a;在SCL为高时&#xff0c;SDA总线被拉低&#xff0c;即出现…

json-server的基本使用

1、mock是什么&#xff1f; mockjs 作用&#xff1a;生成随机数据&#xff0c;拦截 Ajax 请求 目的&#xff1a;很多时候前端开发页面的过程中&#xff0c;后端的接口并没有写好&#xff0c;这个时候需要前端自己定义接口及接口的返回数据的结构体&#xff0c;这个时候就需要…