mybatis源码深度解析

目录

一.生成SqlSessionFactory

1.1通过SqlSessionFactoryBuilder.buid获取

1.2 通过自定义构建Configuration对象构建SqlSessionFactory

二.构建Sqlsession

三.获取mapper代理对象

四.执行查询阶段

4.1通过sqlsession查询结果

4.2委托Executor执行查询

4.3 普通结果集映射

4.4 mybatis嵌套结果集映射


一.生成SqlSessionFactory

   在生成SqlSessionFactory主要是构建configuration核心配置类,该配置类贯穿着Mybatis几乎所有执行步骤,在大多数核心类里面几乎都存在,主要用于存放数据库环境,解析好的MapperProxyFactory(用户构建Mapper代理对象),interceptorChain拦截器,解析好的mappedStatements(用于对sql的描述),二级缓存caches(以名称空间确定使用的Cache,在使用中直接从MappedStatement中获取,在构建时通过MapperBuilderAssistant.useCacheRef(nameSpace)方法调用configuration.getCache(id)获取)等重要配置参数或者解析参数。

1.1通过SqlSessionFactoryBuilder.buid获取

// 1. 读取配置文件,读成字节输入流,注意:现在还没解析
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 2. 解析配置文件,封装Configuration对象   创建DefaultSqlSessionFactory对象

  build方法通过调用 new DefaultSqlSessionFactory(config)构建;config类通过XMLConfigBuilder.parse进行构建,代码如下

// 创建 XMLConfigBuilder 对象
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 执行 XML 解析
// 创建 DefaultSqlSessionFactory 对象 parser.parse()解析xml配置文件
return build(parser.parse());

       parse方法解析

//issue #117 read properties first
// 解析 <properties />
propertiesElement(root.evalNode("properties"));
// 解析 <settings />
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
// 解析 <typeAliases />
typeAliasesElement(root.evalNode("typeAliases"));
// 解析 <plugins />
pluginElement(root.evalNode("plugins"));
// 解析 <objectFactory />
objectFactoryElement(root.evalNode("objectFactory"));
// 解析 <objectWrapperFactory />
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析 <reflectorFactory />
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 赋值 <settings />
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 解析 <environments />
environmentsElement(root.evalNode("environments"));
// 解析 <databaseIdProvider />
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 解析 <typeHandlers />
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析 <mappers />解析成
mapperElement(root.evalNode("mappers"));

mapperElement方法通过调用configuration.addMappers(mapperPackage) ---> 调用configuration.addMappers(mapperPackage) =>调用mapperRegistry.addMappers(packageName)完成MapperProxyFactorymapper代理工厂添加和mapper接口类sql解析封装成MappedStatement

try {
    // 添加到 knownMappers 中
    knownMappers.put(type, new MapperProxyFactory<>(type));
    // 解析 Mapper 的注解配置
    MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
    parser.parse();
    // 标记加载完成
    loadCompleted = true;
} finally {
    // 若加载未完成,从 knownMappers 中移除
    if (!loadCompleted) {
        knownMappers.remove(type);
    }
}

致此通过SQLSessionFactoryBuilder构建SqlSessionFactory完成

1.2 通过自定义构建Configuration对象构建SqlSessionFactory

        具体可参考MybatisSqlSessionFactoryBean.buildSqlSessionFactory()或者SqlSessionFactoryBean.buildSqlSessionFactory方法完成构建具体以MybatisSqlSessionFactoryBean做解析

protected SqlSessionFactory buildSqlSessionFactory() throws Exception {

    final MybatisConfiguration targetConfiguration;

    //使用 MybatisXmlConfigBuilder 而不是 XMLConfigBuilder
    MybatisXMLConfigBuilder xmlConfigBuilder = null;
    if (this.configuration != null) {
        targetConfiguration = this.configuration;
        if (targetConfiguration.getVariables() == null) {
            targetConfiguration.setVariables(this.configurationProperties);
        } else if (this.configurationProperties != null) {
            targetConfiguration.getVariables().putAll(this.configurationProperties);
        }
    } else if (this.configLocation != null) {
        // TODO 使用 MybatisXMLConfigBuilder
        xmlConfigBuilder = new MybatisXMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
        targetConfiguration = xmlConfigBuilder.getConfiguration();
    } else {
        LOGGER.debug(() -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
        // TODO 使用 MybatisConfiguration
        targetConfiguration = new MybatisConfiguration();
        Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
    }

    // TODO 无配置启动所必须的
    this.globalConfig = Optional.ofNullable(this.globalConfig).orElseGet(GlobalConfigUtils::defaults);
    this.globalConfig.setDbConfig(Optional.ofNullable(this.globalConfig.getDbConfig()).orElseGet(GlobalConfig.DbConfig::new));

    // TODO 初始化 id-work 以及 打印骚东西
    targetConfiguration.setGlobalConfig(this.globalConfig);

    // TODO 自定义枚举类扫描处理
    if (hasLength(this.typeEnumsPackage)) {
        Set<Class<?>> classes;
        if (typeEnumsPackage.contains(StringPool.STAR) && !typeEnumsPackage.contains(StringPool.COMMA)
                && !typeEnumsPackage.contains(StringPool.SEMICOLON)) {
            classes = scanClasses(typeEnumsPackage, null);
            if (classes.isEmpty()) {
                LOGGER.warn(() -> "Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration.");
            }
        } else {
            classes = new HashSet<>();
            String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage,
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            Assert.notNull(typeEnumsPackageArray, "not find typeEnumsPackage:" + typeEnumsPackage);
            Stream.of(typeEnumsPackageArray).forEach(typePackage -> {
                try {
                    Set<Class<?>> scanTypePackage = scanClasses(typePackage, null);
                    if (scanTypePackage.isEmpty()) {
                        LOGGER.warn(() -> "Can't find class in '[" + typePackage + "]' package. Please check your configuration.");
                    } else {
                        classes.addAll(scanTypePackage);
                    }
                } catch (IOException e) {
                    throw new MybatisPlusException("Cannot scan class in '[" + typePackage + "]' package", e);
                }
            });
        }
        // 取得类型转换注册器
        TypeHandlerRegistry typeHandlerRegistry = targetConfiguration.getTypeHandlerRegistry();
        classes.stream()
                .filter(Class::isEnum)
                .filter(cls -> IEnum.class.isAssignableFrom(cls) || MybatisEnumTypeHandler.dealEnumType(cls).isPresent())
                .forEach(cls -> typeHandlerRegistry.register(cls, MybatisEnumTypeHandler.class));
    }

    Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
    Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
    Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);

    if (hasLength(this.typeAliasesPackage)) {
        scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
                .filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface())
                .filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
    }

    if (!isEmpty(this.typeAliases)) {
        Stream.of(this.typeAliases).forEach(typeAlias -> {
            targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
            LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");
        });
    }

    if (!isEmpty(this.plugins)) {
        Stream.of(this.plugins).forEach(plugin -> {
            targetConfiguration.addInterceptor(plugin);
            LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
        });
    }

    if (hasLength(this.typeHandlersPackage)) {
        scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
                .filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
                .filter(clazz -> ClassUtils.getConstructorIfAvailable(clazz) != null)
                .forEach(targetConfiguration.getTypeHandlerRegistry()::register);
    }

    if (!isEmpty(this.typeHandlers)) {
        Stream.of(this.typeHandlers).forEach(typeHandler -> {
            targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
            LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
        });
    }

    if (!isEmpty(this.scriptingLanguageDrivers)) {
        Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> {
            targetConfiguration.getLanguageRegistry().register(languageDriver);
            LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'");
        });
    }

    Optional.ofNullable(this.defaultScriptingLanguageDriver).ifPresent(targetConfiguration::setDefaultScriptingLanguage);

    if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
        try {
            targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
        } catch (SQLException e) {
            throw new NestedIOException("Failed getting a databaseId", e);
        }
    }

    Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache);

    if (xmlConfigBuilder != null) {
        try {
            xmlConfigBuilder.parse();
            LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'");
        } catch (Exception ex) {
            throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
        } finally {
            ErrorContext.instance().reset();
        }
    }

    targetConfiguration.setEnvironment(new Environment(MybatisSqlSessionFactoryBean.class.getSimpleName(),
            this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
            this.dataSource));



    //解析mapperLocations配置mybatis原生框架不支持改方式解析是通过Mappers 对mapper接口进行解析,反推mapper接口对应的xml文件进行解析
    //对mybatis来说mapper接口与xml没有直接的绑定,是通过method构建成statementId然后通过configuration缓存statement的map中获取
    //具体映射可参考mapperProxyFactory类的newInstance方法 =>new MapperProxy<>(sqlSession, mapperInterface, methodCache) =>
    // invoke => cachedMapperMethod(Method method) => new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())
    // => this.command = new SqlCommand(config, mapperInterface, method);
    //    this.method = new MethodSignature(config, mapperInterface, method);
    // => resolveMappedStatement(mapperInterface, methodName, declaringClass,configuration)绑定xml方法
    if (this.mapperLocations != null) {
        if (this.mapperLocations.length == 0) {
            LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found.");
        } else {
            for (Resource mapperLocation : this.mapperLocations) {
                if (mapperLocation == null) {
                    continue;
                }
                try {
                    XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
                            targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
                    xmlMapperBuilder.parse();
                } catch (Exception e) {
                    throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
                } finally {
                    ErrorContext.instance().reset();
                }
                LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");
            }
        }
    } else {
        LOGGER.debug(() -> "Property 'mapperLocations' was not specified.");
    }

    final SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(targetConfiguration);

    // TODO SqlRunner
    SqlHelper.FACTORY = sqlSessionFactory;

    // TODO 打印骚东西 Banner
    if (globalConfig.isBanner()) {
        System.out.println(" _ _   |_  _ _|_. ___ _ |    _ ");
        System.out.println("| | |\\/|_)(_| | |_\\  |_)||_|_\\ ");
        System.out.println("     /               |         ");
        System.out.println("                        " + MybatisPlusVersion.getVersion() + " ");
    }

    return sqlSessionFactory;
}

致此通过直接构建configuration类完成sqlSessionFactory构建

二.构建Sqlsession

       获取sqlsession

  SqlSession sqlSession = sqlSessionFactory.openSession();
 public SqlSession openSession() {
        //getDefaultExecutorType()传递的是SimpleExecutor
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
    }
    /**
     * @param execType   执行器类型
     * @param level      事务隔离级别
     * @param autoCommit 是否自动提交事务
     * @return SQLSession
     */
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
            // 获得 Environment 对象
            final Environment environment = configuration.getEnvironment();
            // 创建 Transaction 对象
            final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            // 创建 Executor 对象 在此方法涉及mybatis插件 通过轮流调用Interceptor.plugin方法完成代理拦截符合条件的方法,将方法,拦截对象,
            // 方法参数封装成invocation传入intercept方法供用户完成插件逻辑
            final Executor executor = configuration.newExecutor(tx, execType);
            // 创建 DefaultSqlSession 对象
            return new DefaultSqlSession(configuration, executor, autoCommit);
        } catch (Exception e) {
            //则关闭 事务
            closeTransaction(tx); // may have fetched a connection so lets call close()
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }

   创建执行器Executor


    /**
     * 创建 Executor 对象
     *
     * @param transaction 事务对象
     * @param executorType 执行器类型
     * @return Executor 对象
     */
    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        // 获得执行器类型
        executorType = executorType == null ? defaultExecutorType : executorType; // 使用默认
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType; // 使用 ExecutorType.SIMPLE
        // 创建对应实现的 Executor 对象
        Executor executor;
        if (ExecutorType.BATCH == executorType) {
            //批量执行执行器
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            //重用StatementHandler
            executor = new ReuseExecutor(this, transaction);
        } else {
            //简单执行器
            executor = new SimpleExecutor(this, transaction);
        }
        // 如果开启缓存,创建缓存执行器,内部通过对executor进行包装,查询数据时二级缓存不存在时通过executor完成crud
        if (cacheEnabled) {
            executor = new CachingExecutor(executor);
        }
        // 应用插件
        executor = (Executor) interceptorChain.pluginAll(executor);
        return executor;
    }

          致此执行器创建完毕然后通过DefaultSqlSession构造方法创建SqlSession致此SqlSession创建完成

三.获取mapper代理对象

        

sqlSession.getMapper(Mapper.class);

从configuration中获取mapper,可以看出configuration的作用有多重要 

    @Override
    public <T> T getMapper(Class<T> type) {
        return configuration.getMapper(type, this);
    }

从MapperRegistry中获取

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return mapperRegistry.getMapper(type, sqlSession);
    }

生成mapper的代理对象

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        // 获得 MapperProxyFactory 对象,回想前面的存入MapperProxyFactory对象
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        // 不存在,则抛出 BindingException 异常
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        }
        /// 通过动态代理工厂生成实例。
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
            throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
    }

在newInstance方法中完成对mapper方法的代理

   public T newInstance(SqlSession sqlSession) {
        // 创建了JDK动态代理的invocationHandler接口的实现类mapperProxy,传入methodCache是为了        
        // 对解析后的MapperMethod做缓存方便后面使用的时候直接获取,通过execute方法传入 
        // sqlsession直接执行,解析实在invoke代理方法中执行
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        // 调用了重载方法
        return newInstance(mapperProxy);
    }

MapperProxy的代理逻辑invoke方法解析

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            // 如果是 Object 定义的方法,直接调用
            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);
        }
        // 获得 MapperMethod 对象,并缓存
        // 该方法通过MapperMethod 的构造方法以及MethodSignature构造方法
        // 完成对方法command以及MethodSignature的解析,然后封装成MapperMethod对象
        // 通过调用execute方法,进入sqlsession查询步骤
       final MapperMethod mapperMethod = cachedMapperMethod(method);
        // 重点在这:MapperMethod最终调用了执行的方法
        return mapperMethod.execute(sqlSession, args);
    }

 new SqlCommand(config, mapperInterface, method)方法解析

        public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
            final String methodName = method.getName();
            final Class<?> declaringClass = method.getDeclaringClass();
            // 获得 MappedStatement 对象
            MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
                    configuration);
            if (ms == null) {
                if (method.getAnnotation(Flush.class) != null) {
                    name = null;
                    type = SqlCommandType.FLUSH;
                } else {
                    throw new BindingException("Invalid bound statement (not found): "
                            + mapperInterface.getName() + "." + methodName);
                }
            } else {
                name = ms.getId();
                type = ms.getSqlCommandType();
                if (type == SqlCommandType.UNKNOWN) { 
                    throw new BindingException("Unknown execution method for: " + name);
                }
            }
        }
new MethodSignature(config, mapperInterface, method)
        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);
        }

致此获取mapper代理对象结束,注意sqlsession每获取一次mapper都会重新生成一个代理对象。

注:最终执行都是通过sqlSession进行crud操作,前面这一些操作仅仅是为了对代理mapper,解析出mapper对应方法对应的sqlsession对应的那个方法去执行,在调用mapper方法时调用sqlsession对应的方法,对结果进行封装返回。

    mybatis执行查询是以sqlsession进行,用完之后需要重新构建,之所以使用sqlsession是为了更简单的处理并发,和降低代码编写难度,复核会话的定义。

     spring在整合mybatis,写了一个sqlsessionTemplate,实现了sqlsession接口;通过对mapper的代理,拦截对应的方法,创建Mybatis的sqlsession,委托调用创建的Mybatis的sqlsession完成crud,将事物与mybatis剥离,自己进行管理;通过FactoryBean设置构造函数参数实例化MapperFactoryBean通getObject获取sqlSessionTemplate完成整合,后面做详细介绍。

可以参考MapperFactoryBean和SQLSessionTemplate类以及ClassPathMapperScanner.processBeanDefinitions方法

四.执行查询阶段

        注:只做查询解析

4.1通过sqlsession查询结果

    @Override
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
            // 通过statementId该Id为名称空间加上方法名 获得 MappedStatement 对象
            MappedStatement ms = configuration.getMappedStatement(statement);
            // 查询
            return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
        } finally {
            ErrorContext.instance().reset();
        }
    }

4.2委托Executor执行查询

        

   这里对BaseExecutor做解析

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        //根据传入的参数动态获得SQL语句,最后返回用BoundSql对象表示
        BoundSql boundSql = ms.getBoundSql(parameter);
        //为本次查询创建缓存的Key
        CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
        // 查询
        return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }

 ms.getBoundSql(parameter)解析

    public BoundSql getBoundSql(Object parameterObject) {
        // 获得 BoundSql 对象 sqlsource在构建mapperstatement构建,用于对sql解析
        // 该SqlSource实现类有 DynamicSqlSource动态sql解析
        //  ProviderSqlSource@ProviderXXX 注解的 SqlSource 实现类
        //  RawSqlSource 通过委托该类获取具体的SQLSource(DynamicSqlSource,StaticSqlSource                 
        //   , ProviderSqlSource)
        //  StaticSqlSource 静态sql解析
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings == null || parameterMappings.isEmpty()) {
            boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
        }

        // check for nested result maps in parameter mappings (issue #30)
        // 判断传入的参数中,是否有内嵌的结果 ResultMap 。如果有,则修改 hasNestedResultMaps 为 true
        // 存储过程相关,暂时无视
        for (ParameterMapping pm : boundSql.getParameterMappings()) {
            String rmId = pm.getResultMapId();
            if (rmId != null) {
                ResultMap rm = configuration.getResultMap(rmId);
                if (rm != null) {
                    hasNestedResultMaps |= rm.hasNestedResultMaps();
                }
            }
        }

        return boundSql;
    }

     执行查询

    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());
        // 已经关闭,则抛出 ExecutorException 异常
        if (closed) {
            throw new ExecutorException("Executor was closed.");
        }
        // 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。
        if (queryStack == 0 && ms.isFlushCacheRequired()) {
            clearLocalCache();
        }
        List<E> list;
        try {
            // 用于记录调用链是否完成,完成后执行懒加载,用于解决循环依赖问题
            queryStack++;
            // 从一级缓存中,获取查询结果
            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();
            }
            // 清空懒加载
            deferredLoads.clear();
            if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                // 清除缓存
                clearLocalCache();
            }
        }
        return list;
    }
queryFromDatabase解析
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        // 在一级缓存中,添加占位符用于处理延迟加载,DeferredLoad#canLoad()在结果集处理中处理嵌                
        // 套子查询,出现循环依赖时,存入DeferredLoad;待所有查询完成后通过            
        //  DeferredLoad#canLoad()从缓存中获取结果设置到属性中
        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;
    }

进入doQuery方法

在解读该方法时先对执行器Executor进行解读

该类的实现类有4个,定义了Executor接口; mybatis为了复用公用方法使用了模板设计模式,在BaseExecutor中实现公用方法后定义了需要需要子类完成不同功能的方法(如下图所示)

在baseExecutor中调用抽象方法,子类实现baseExecutor抽象方法,

完成复用statement的实现类

 完成批量操作实现类

 完成简单操作实现类

 下面对CacheExecutor二级缓存做详细解读:

在CacheExecutor中实现了Executor接口通过委托BaseExecutor的实现类执行crud,将执行结果存入Cache,或在执行前重缓存获取数据,在存入缓存前必须在事务提交后通过缓存事务类提交缓存事务,存入缓存,中途失败则不存入缓存,一但出现修改则清空事务缓存中的数据,设置MappedStatement.flushCacheRequired=true(在BaseExecutor.query中清空缓存代码如下)

注意只有提交事务后二级缓存才会存入查询的数据,如果在分布条件下不建议使用二级缓存会出现严重的问题,例如A服务查询了一条数据存入缓存(自己实现的缓存,存入redis)中后,A服务有修改了该条数据,清空事务缓存,编辑cache失效;但此时A服务并未去对该名称空间下的数据做查询,这样缓存中的数据任然有效,此时B服务对该条数据做查询,就会导致直接从二级缓存中获取数据,导致查询到失效数据。

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.");
    }
    // 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
​​​​​​​}

,只提交事务是才会提交事务缓存中的数据到cache中;

下面我们以SimpleExecutor 为例对doQuery方法做解读

    @Override
    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对象(该对象用于创建和设置查询参数), wrapper为自己
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 创建jdbc中的statement对象,设置sql参数
            stmt = prepareStatement(handler, ms.getStatementLog());
            // 执行 StatementHandler  ,进行读操作,该statement已经准备完毕直接执行查询即可
            return handler.query(stmt, resultHandler);
        } finally {
            // 关闭 StatementHandler 对象
            closeStatement(stmt);
        }
    }

下面对configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql)进行解读

该方法主要用于创建RoutingStatementHandler,在该类构造方法中通过MappedStatement.getStatementType构建不同的StatementHandler后将statementHandler作为参数应用插件

    // 创建 StatementHandler 对象
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 创建 RoutingStatementHandler 对象
        StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        // 应用插件
        statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
        return statementHandler;
    }

下面对StatementHandler做接读

        该类的主要作用是用于创建或处理java.sql.Statement -> SimpleStatementHandler、java.sql.PreparedStatement -> PreparedStatementHandler、java.sql.CallableStatement -> CallableStatementHandler

设置参数等,该类的实现方式与Executor类似,抽象StatementHandler接口后再BaseStatementHandler中实现可复用的方法,调用子类实现的抽象方法;委托到具体的实现类是通过RoutingStatementHandler该类的构造方法

    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 根据不同的类型,创建对应的 StatementHandler 实现类
        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());
        }
    }

        适配具体的实现类,然后委托实现类完成statement的创建复用参数设置,结果集处理。

下面对BaseExecutor的构造方法做解读

   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) { 
            generateKeys(parameterObject);
            // 创建 BoundSql 对象
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }
        this.boundSql = boundSql;

        // 创建 ParameterHandler 对象,此方法用于应用ParameterHandler插件
        this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
        // 创建 ResultSetHandler 对象,此方法用于应用ResultSetHandler插件
        this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
    }

致此完成了statementHandler的创建完成,statement

下面对handler.query(stmt, resultHandler)做解析

我们以常用sql预编译PreparedStatementHandler做解析,传入该方法的statement已经是处理完毕,直接执行查询的处理代码如下

 // 初始化 StatementHandler 对象
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        // 获得 Connection 对象
        Connection connection = getConnection(statementLog);
        // 创建 Statement 或 PrepareStatement 对象
        stmt = handler.prepare(connection, transaction.getTimeout());
        // 设置 SQL 上的参数,该handler为RoutingStatementHandler
        handler.parameterize(stmt);
        return stmt;
    }

执行查询

 @Override
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        // 执行查询
        ps.execute();
        // 处理结果集
        return resultSetHandler.handleResultSets(ps);
    }

4.3 普通结果集映射

resultSetHandler为BaseExecutor构造方法内 configuration.newResultSetHandler创建的DefaultResultSetHandler

进入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;
        // 获得首个 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 resultMap = resultMaps.get(resultSetCount);
            // 处理 ResultSet
            handleResultSet(rsw, resultMap, multipleResults, null);
            // 获得下一个 ResultSet 对象,并封装成 ResultSetWrapper 对象
            rsw = getNextResultSet(stmt);
            // 清理
            cleanUpAfterHandlingResultSet();
            // resultSetCount ++
            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);
    }

      下面对handleResultSet做解读

    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 defaultResultHandler = new DefaultResultHandler(objectFactory);
                    // 处理 ResultSet 返回的每一行 Row
                    handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
                    multipleResults.add(defaultResultHandler.getResultList());
                } else {
                    // 处理 ResultSet 返回的每一行 Row
                    handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
                }
            }
        } finally {
            // 关闭ResultSet
            closeResultSet(rsw.getResultSet());
        }
    }

下面对handleRowValues做解读

    // 处理 ResultSet的每一行数据
    public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        // 处理嵌套查询
        if (resultMap.hasNestedResultMaps()) {
            // 校验不要使用 RowBounds
            ensureNoRowBounds();
            // 校验resultHandler,安全检测开启的情况下校验结果集是否有序,防止嵌套查询导致的
            // 内存溢出,如果无序的话在自定义的ResultHandler中就可能存在对前面结果集的引用,            
            // 一直将结果集保存导致内存中导致内存溢出        
            // 方便溢出
            checkResultHandler();
            // 处理嵌套映射的结果
            handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        // 处理简单映射
        } else {
            // 处理简单映射结果
            handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
        }
    }

下面对handleRowValuesForSimpleResultMap做解读

    // 处理简单映射
    private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
        DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
        // 获得ResultSet
        ResultSet resultSet = rsw.getResultSet();
        //跳到rowBounds指定的开始位置
        skipRows(resultSet, rowBounds);
        // 循环处理每一行row
        while (shouldProcessMoreRows(resultContext, rowBounds) // 判断是否继续处理ResultSet
                && !resultSet.isClosed() // ResultSet是否关闭
                && resultSet.next()) { // ResultSet是否存在下一条
            // 根据该行记录以及 ResultMap.discriminator获取对应的ResultMap对象
            // 该对象用于处理jdbc与实体属性的映射
            ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
            // 通过ResultMap对ResultSet与结果对象做映射,处理懒加载,内部对象映射等
            Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
            // 将映射创建的结果对象添加到ResultHandler中
            storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
        }
    }

下面对resolveDiscriminatedResultMap进行解读

    public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
        // 记录处理过Discriminator对应的ResultMap的编号
        Set<String> pastDiscriminators = new HashSet<>();
        // 在resultMap中存在Discriminator对象,则通过其获取ResultMap对象,
        // 用于处理一个结果对应多个实现类,根据结果的不同选择不同的实现类
        // 例如结果需要映射到A对象,A对象里面有个实现B接口的对象,B对象的实现类有  
        // d,g,k 根据A对象id对3求余确定使用对应的对象
        Discriminator discriminator = resultMap.getDiscriminator();
        while (discriminator != null) { // 因为 Discriminator 可以嵌套 Discriminator ,所以是一个递归的过程
            // 获得Discriminator字段,在ResultSet中的值
            final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
            // 从 Discriminator 获取该值对应的ResultMap的id
            final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
            // 存在,则使用该ResultMap对象继续遍历
            if (configuration.hasResultMap(discriminatedMapId)) {
                // 获得该 ResultMap 对象
                resultMap = configuration.getResultMap(discriminatedMapId);
                // 出现重复结束循环
                Discriminator lastDiscriminator = discriminator;
                discriminator = resultMap.getDiscriminator();
                if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
                    break;
                }
            // 如果不存在,直接结束循环
            } else {
                break;
            }
        }
        return resultMap;
    }

接下来对getRowValue做解读

该方法主要通过resultMap对resultSet与结果对象做映射

    private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
        // 用于懒加载,将懒加载的查询封装成该对象通过load方法查询结果并通过
        // metaObject设置到原对象的属性中
        final ResultLoaderMap lazyLoader = new ResultLoaderMap();
        // 创建结果对象,若该结果集存在懒加载则对对象的get方法做代理
        // 在调用get方法时通过lazyLoader.loadResult 查询结果并形成闭环
        Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
        if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
            // 创建MetaObject对象用于给映射对象设置属性值
            final MetaObject metaObject = configuration.newMetaObject(rowValue);
            boolean foundValues = this.useConstructorMappings;
            // 是否开启自动映射功能,若开启则对未确定的列进行自动映射
            if (shouldApplyAutomaticMappings(resultMap, false)) {
                // 自动映射
                foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
            }
            // 映射ResultMap中propertyResultMappings相关列
            foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
            // 改行映射已完成
            foundValues = lazyLoader.size() > 0 || foundValues;
            // 如果映射失败则返回null
            rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
        }
        return rowValue;
    }

下面对applyPropertyMappings方法做解读

    // 映射结果集
    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;
        // 遍历ResultMapping并做值映射
        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
                // 如果含有嵌套结果集映射,忽略该字段,在applyNestedResultMappings方法处理嵌    
                // 套映射          
                column = null;
            }
            if (propertyMapping.isCompositeResult() // 组合
                    || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) // 属于 mappedColumnNames
                    || propertyMapping.getResultSet() != null) { // 存储过程
                // 获得指定字段的值
                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())) {
                    metaObject.setValue(property, value);
                }
            }
        }
        return foundValues;
    }

下面对getPropertyMappingValue方法做解读,该方法完成获取属性值以及嵌套查询

    // 获取字段的值
    private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
            throws SQLException {
        if (propertyMapping.getNestedQueryId() != null) {//嵌套查询直接调用getNestedQueryMappingValue方法进行查询
            return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
        } 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);
        }
    }

下面对嵌套查询方法getNestedQueryMappingValue做解读

    // 嵌套查询方法
    private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
            throws SQLException {
        // 获得子查询查询的
        final String nestedQueryId = propertyMapping.getNestedQueryId();
        // 获得属性名
        final String property = propertyMapping.getProperty();
        // 获得嵌套查询MappedStatement
        final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
        // 获得嵌套查询参数类型
        final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
        // 获得嵌套查询的参数
        final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
        Object value = null;
        if (nestedQueryParameterObject != null) {
            // 获取BoundSql
            final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
            // 获得取 CacheKey
            final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
            final Class<?> targetType = propertyMapping.getJavaType();
            // 检查缓存是否以存在,前面在进入查询是设置过占位符到缓存中,此处用于解决循环依赖
            if (executor.isCached(nestedQuery, key)) {
                // 若果存在创建 DeferredLoad 对象,通过该对象从缓存中加载并设置属性值
                executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
                // 返回以定义标记
                value = DEFERED;
            } else {// 缓存中不存在
                // 创建 ResultLoader 对象 用于加载结果
                final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
                // 处理延时加载
                if (propertyMapping.isLazy()) {
                    // 该属性配置了延迟加载,将其添加到ResultLoader.loaderMap中,通过代理过的get方法调用resultLoader.loadResult方法查询结果并返回
                    // get代理方法在创建结果对象时做的代理
                    lazyLoader.addLoader(property, metaResultObject, resultLoader);
                    // 返回已定义
                    value = DEFERED;
                } else {// 直接加载结果
                    value = resultLoader.loadResult();
                }
            }
        }
        return value;
    }

下面对 resultLoader.loadResult()方法做解读

    /**
     * 查询结果并获取结果
     *
     * @return 结果
     */
    public Object loadResult() throws SQLException {
        // 执行查询
        List<Object> list = selectList();
        // 获取结果
        resultObject = resultExtractor.extractObjectFromList(list, targetType);
        // 返回结果
        return resultObject;
    }

查询结果解析结果结束返回

4.4 mybatis嵌套结果集映射

大概逻辑为:

        假设结果集映射含有A,B,C三个对象其中B为A的属性对象,关联关系为A的id,C为B的属性对象关联关系为B的id;循环遍历查询出来的结果集,我们以遍历过程中的一行结果记录为例,先为A对象创建rowKey(xml文件中resultMap 的<id>属性作为标识创建,有几个id就用几个id作为区分多行数数据中应该属于同一对象),从nestedResultObjects缓存中获取是否存在相同的对象数据,如果不存在,则对A对象的普通属性做映射,映射后将A对象以rowKey作为Key,A对象作为Value存入nestedResultObjects中,  如果nestedResultObjects存在则对A对象中的子对象B做映射,在映射B对象的过程中同样创建rowkey后创建组合键combinedKey,然后以combinedKey作为key从nestedResultObjects或B对象,以同样的逻辑直到所有嵌套结果集全都映射完成

下面为对核心代码的注释

        while (shouldProcessMoreRows(resultContext, rowBounds) 
                && !resultSet.isClosed() 
                && resultSet.next()) { 
            // 处理鉴别器,获取ResultMap 
            final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
             //创建rowKey
            final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
            Object partialObject = nestedResultObjects.get(rowKey);
            //结果集有序的情况下
            if (mappedStatement.isResultOrdered()) {
                if (partialObject == null && rowValue != null) {
                    nestedResultObjects.clear();
                    storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
                }
                rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
            } else {
                //获取获取映射结果集 partialObject作为判断对象普通属性是否已映射
                //不为空已映射,为空未映射
                rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
                if (partialObject == null) {
                    storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
                }
            }
        }

下面对getRowValue方法做注释

    private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
        final String resultMapId = resultMap.getId();
        Object rowValue = partialObject;
        //从缓存中获取到,则认为改行父对象普通属性已解析,只需解析内嵌对象
        if (rowValue != null) {
            final MetaObject metaObject = configuration.newMetaObject(rowValue);
            //将父对象存入ancestorObjects中防止循环解析问题
            putAncestor(rowValue, resultMapId);
            //映射内嵌结果对象
            applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
            //将父对象重ancestorObjects中移除
            ancestorObjects.remove(resultMapId);
        } else
        //从缓存中未获取到,则认为即要映射普通属性也要映射嵌套对象
        {
            final ResultLoaderMap lazyLoader = new ResultLoaderMap();
            //创建对象,若存在懒加载对get方法做代理
            rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
            
            if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
                final MetaObject metaObject = configuration.newMetaObject(rowValue);
                boolean foundValues = this.useConstructorMappings;
                if (shouldApplyAutomaticMappings(resultMap, true)) {
                    foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
                }
                //为普通属性赋值
                foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
                //将父对象存入ancestorObjects中防止循环解析问题
                putAncestor(rowValue, resultMapId);
                //映射嵌套对象
                foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
                //将父对象重ancestorObjects中移除
                ancestorObjects.remove(resultMapId);
                foundValues = lazyLoader.size() > 0 || foundValues;
                rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
            }
            if (combinedKey != CacheKey.NULL_CACHE_KEY) {
                nestedResultObjects.put(combinedKey, rowValue);
            }
        }
        return rowValue;
    }

下面对applyNestedResultMappings方法作注释

    private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
        boolean foundValues = false;
        for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
            final String nestedResultMapId = resultMapping.getNestedResultMapId();
            // nestedResultMapId不为空则为内嵌对象
            if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
                try {
                    //获取字段前缀
                    final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
                    // 获取ResultMap
                    final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
                    if (resultMapping.getColumnPrefix() == null) {
                        // try to fill circular reference only when columnPrefix
                        // is not specified for the nested result map (issue #215)
                        // 仅在 columnPrefix 为空时,尝试填充循环引用,用于嵌套结果映射
                        // 前面有存入过
                        Object ancestorObject = ancestorObjects.get(nestedResultMapId);
                        if (ancestorObject != null) {
                            // 如是出现循环依赖,直接使用ancestorObject
                            if (newObject) {
                                linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
                            }
                            //不进行后续步骤
                            continue;
                        }
                    }

                    // 创建内嵌对象的CacheKey
                    final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
                    //创建组合Key
                    final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
                    // 从nestedResultObjects中获取
                    Object rowValue = nestedResultObjects.get(combinedKey);
                    boolean knownValue = rowValue != null;

                    // 如果当前对象是集合嵌套,则对集合对象进行初始化
                    instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);

                    // 不为空的对象属性不能为空
                    if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
                        // 处理嵌套对象的属性值,再次进入getRowValue,同样的逻辑
                        rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
                        // 如果嵌套对象非空
                        if (rowValue != null && !knownValue) {
                            linkObjects(metaObject, resultMapping, rowValue);
                            foundValues = true;
                        }
                    }
                } catch (SQLException e) {
                    throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
                }
            }
        }
        return foundValues;
    }

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值