揭秘Mybatis(二)_Mybatis工作原理

引:了解完Mybatis的架构,那么它的执行流程又是怎么样的呢?

Mybatis主要组件及工作流程

主要组件

  1. Configuration:MyBatis所有的配置信息都维持在Configuration对象之中
  2. SqlSession:作为MyBatis接口层的AOP,表示和数据库交互的会话,完成必要数据库增删改查功能
  3. Executor:MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
  4. StatementHandler:封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合
  5. ParameterHandler:负责对用户传递的参数转换成JDBC Statement 所需要的参数
  6. resultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
  7. TypeHandler:负责java数据类型和jdbc数据类型之间的映射和转换
  8. MappedStatement:MappedStatement维护了一条节点的封装
  9. SqlSource:负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
  10. BoundSql:表示动态生成的SQL语句以及相应的参数信息

工作流程图

workflow

这张图也超级棒(Nice 兄Dei),在下面参考也将看到出处。我们下面的源码分析也会参考这张图。

Mybatis初始化源码分析

  1. 获取配置文件创建SqlSessionFactory

    1
    2
    3
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  2. 进入到SqlSessionFactory的build方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;
    try {
    // 解析刚刚创建的配置文件文件流
    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    var5 = this.build(parser.parse());
    } catch (Exception var14) {
    throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    } finally {
    ErrorContext.instance().reset();
    try {
    inputStream.close();
    } catch (IOException var13) {
    ;
    }
    }
    return var5;
    }
  3. 会进入到XMLConfigBuilder的parse方法去解析配置文件的具体内容生成Configuration对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public Configuration parse() {
    if(this.parsed) {
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    } else {
    this.parsed = true;
    // 解析配置文件
    this.parseConfiguration(this.parser.evalNode("/configuration"));
    return this.configuration;
    }
    }

    private void parseConfiguration(XNode root) {
    try {
    // 解析<properties>节点,数据源配置文件
    this.propertiesElement(root.evalNode("properties"));
    // 解析<typeAliases>节点,别名节点
    this.typeAliasesElement(root.evalNode("typeAliases"));
    // 解析<plugins>节点,插件节点
    this.pluginElement(root.evalNode("plugins"));
    // 解析<objectFactory>节点
    this.objectFactoryElement(root.evalNode("objectFactory"));
    // 解析<reflectorFactory>节点
    this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    // 解析<settings>节点
    this.settingsElement(root.evalNode("settings"));
    // 解析<environments>节点
    this.environmentsElement(root.evalNode("environments"));
    this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    this.typeHandlerElement(root.evalNode("typeHandlers"));
    // 解析<mappers>节点,很重要
    this.mapperElement(root.evalNode("mappers"));
    } catch (Exception var3) {
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
    }
    }
  4. 我们最关心的可能就是mapper的解析了,所以我们进入mapperElement方法看看:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    private void mapperElement(XNode parent) throws Exception {
    if(parent != null) {
    Iterator i$ = parent.getChildren().iterator();

    while(true) {
    // 遍历<mappers>下所有子节点
    while(i$.hasNext()) {
    XNode child = (XNode)i$.next();
    String resource;
    // 如果当前节点为<package>
    if("package".equals(child.getName())) {
    // 获取<package>的name属性(该属性值为mapper class所在的包名)
    resource = child.getStringAttribute("name");
    // 将该包下的所有Mapper Class注册到configuration的mapperRegistry容器中
    this.configuration.addMappers(resource);
    } else {
    // 依次获取resource、url、class属性
    resource = child.getStringAttribute("resource");
    String url = child.getStringAttribute("url");
    String mapperClass = child.getStringAttribute("class");
    XMLMapperBuilder mapperParser;
    InputStream inputStream;
    // 解析resource属性(Mapper.xml文件的路径)
    if(resource != null && url == null && mapperClass == null) {
    ErrorContext.instance().resource(resource);
    // 将Mapper.xml文件解析成输入流
    inputStream = Resources.getResourceAsStream(resource);
    // 使用XMLMapperBuilder解析Mapper.xml,并将Mapper Class注册进configuration对象的mapperRegistry容器中
    mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
    // 这个很重要,看看具体怎么解析
    mapperParser.parse();
    } else if(resource == null && url != null && mapperClass == null) {
    // 解析url属性(Mapper.xml文件的路径)
    ErrorContext.instance().resource(url);
    inputStream = Resources.getUrlAsStream(url);
    mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
    mapperParser.parse();
    } else {
    // 解析class属性(Mapper Class的全限定名)
    if(resource != null || url != null || mapperClass == null) {
    throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
    }
    // 将Mapper Class的权限定名转化成Class对象
    Class<?> mapperInterface = Resources.classForName(mapperClass);
    this.configuration.addMapper(mapperInterface);
    }
    }
    }

    return;
    }
    }
    }


    public void parse() {
    if(!this.configuration.isResourceLoaded(this.resource)) {
    // 解析<mapper>节点
    this.configurationElement(this.parser.evalNode("/mapper"));
    // 将该Mapper.xml添加至configuration的LoadedResource容器中,下回无需再解析
    this.configuration.addLoadedResource(this.resource);
    // 将该Mapper.xml对应的Mapper Class注册进configuration的mapperRegistry容器中,很重要,下马需要仔细看看
    this.bindMapperForNamespace();
    }

    this.parsePendingResultMaps();
    this.parsePendingChacheRefs();
    this.parsePendingStatements();
    }
  5. bindMapperForNamespace极其重要,因为这里会给Mapper接口创建动态代理对象,我们看看源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    private void bindMapperForNamespace() {
    // 获取当前映射文件对应的DAO接口的全限定名
    String namespace = this.builderAssistant.getCurrentNamespace();
    if(namespace != null) {
    // 将全限定名解析成Class对象
    Class boundType = null;
    try {
    boundType = Resources.classForName(namespace);
    } catch (ClassNotFoundException var4) {
    ;
    }
    if(boundType != null && !this.configuration.hasMapper(boundType)) {
    // 将当前Mapper.xml标注为已加载下回就不用再加载了
    this.configuration.addLoadedResource("namespace:" + namespace);
    // 将Mapper接口的Class对象注册进configuration中(其实是在configuration的MapperRegistry里面)
    this.configuration.addMapper(boundType);
    }
    }
    }
  6. 我们再进入到this.configuration.addMapper方法中看看会做些什么:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public <T> void addMapper(Class<T> type) {
    this.mapperRegistry.addMapper(type);
    }

    public <T> void addMapper(Class<T> type) {
    if(type.isInterface()) {
    if(this.hasMapper(type)) {
    throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
    }
    boolean loadCompleted = false;
    try {
    // 创建MapperProxyFactory对象(用于创建DAO接口的代理对象),并put进knownMappers中
    // 为后面的创建Mapper代理对象做准备
    this.knownMappers.put(type, new MapperProxyFactory(type));
    MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
    parser.parse();
    loadCompleted = true;
    } finally {
    if(!loadCompleted) {
    this.knownMappers.remove(type);
    }
    }
    }

    }
  7. 等Mapper全都解析好之后,初始化工作基本就完成了。

Mybatis工作流程源码分析

  1. 创建SqlSession对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    SqlSession sqlSession = sqlSessionFactory.openSession();

    public SqlSession openSession() {
    // 从数据源创建SqlSession会话对象
    return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
    }

    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;

    DefaultSqlSession var8;
    try {
    // 初始化读取了Environment里面的数据源以及事务配置
    Environment environment = this.configuration.getEnvironment();
    // 获取事务工厂
    TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    // 生成MyBatis执行器
    Executor executor = this.configuration.newExecutor(tx, execType);
    // 创建DefaultSqlSession对象
    var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
    } catch (Exception var12) {
    this.closeTransaction(tx);
    throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
    } finally {
    ErrorContext.instance().reset();
    }

    return var8;
    }
  2. 从SqlSession对象获得Mapper(后面会看到这是个代理对象),看看执行流程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    public <T> T getMapper(Class<T> type) {
    // 进入configuration
    return this.configuration.getMapper(type, this);
    }

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 调用configuration对象的apperRegistry的getMapper方法
    return this.mapperRegistry.getMapper(type, sqlSession);
    }

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 这个是在初始化过程中解析mapper时生成的,现有看到了Mapper对象的工厂
    MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if(mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
    try {
    // 生成Mapper实例,进入看看
    return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception var5) {
    throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
    }
    }
    }

    public T newInstance(SqlSession sqlSession) {
    // 原来这个还是个代理对象
    MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
    return this.newInstance(mapperProxy);
    }
  3. 获得Mapper代理对象我看看他是怎么执行Mapper接口的方法的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    List<User> userList = userMapper.selectList();

    // 一进去就发现直接到了invoke方法,相当于把方法的执行都交给了代理对象去执行
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if(Object.class.equals(method.getDeclaringClass())) {
    try {
    return method.invoke(this, args);
    } catch (Throwable var5) {
    throw ExceptionUtil.unwrapThrowable(var5);
    }
    } else {
    // 从当前代理对象处理类MapperProxy的methodCache属性中获取MapperMethod对象,如果methodCache中没有就创建并加进去。
    MapperMethod mapperMethod = this.cachedMapperMethod(method);
    // 该方法就会调用JDBC执行相应的SQL语句
    return mapperMethod.execute(this.sqlSession, args);
    }
    }

    public Object execute(SqlSession sqlSession, Object[] args) {
    Object param;
    Object result;
    // 比对mapper标签
    if(SqlCommandType.INSERT == this.command.getType()) {
    param = this.method.convertArgsToSqlCommandParam(args);
    result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
    } else if(SqlCommandType.UPDATE == this.command.getType()) {
    param = this.method.convertArgsToSqlCommandParam(args);
    result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
    } else if(SqlCommandType.DELETE == this.command.getType()) {
    param = this.method.convertArgsToSqlCommandParam(args);
    result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
    } else {
    if(SqlCommandType.SELECT != this.command.getType()) {
    throw new BindingException("Unknown execution method for: " + this.command.getName());
    }
    if(this.method.returnsVoid() && this.method.hasResultHandler()) {
    this.executeWithResultHandler(sqlSession, args);
    result = null;
    } else if(this.method.returnsMany()) {
    // 最终会进入这里
    result = this.executeForMany(sqlSession, args);
    } else if(this.method.returnsMap()) {
    result = this.executeForMap(sqlSession, args);
    } else {
    param = this.method.convertArgsToSqlCommandParam(args);
    result = sqlSession.selectOne(this.command.getName(), param);
    }
    }
    if(result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
    throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
    } else {
    return result;
    }
    }
  4. MapperMethod到底如何去执行executeForMap(sqlSession, args)的呢?我们可以继续进入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    // 将参数拼接到SQL
    Object param = this.method.convertArgsToSqlCommandParam(args);
    List result;
    if(this.method.hasRowBounds()) {
    RowBounds rowBounds = this.method.extractRowBounds(args);
    result = sqlSession.selectList(this.command.getName(), param, rowBounds);
    } else {
    // 进入到这里,让sqlSession来处理
    result = sqlSession.selectList(this.command.getName(), param);
    }

    return !this.method.getReturnType().isAssignableFrom(result.getClass())?(this.method.getReturnType().isArray()?this.convertToArray(result):this.convertToDeclaredCollection(sqlSession.getConfiguration(), result)):result;
    }

    public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
    }

    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    List var6;
    try {
    // 根据StatementId(com.todorex.UserMapper.selectList),
    // 在配置对象Configuration中查找相对应的MappedStatement
    MappedStatement ms = this.configuration.getMappedStatement(statement);
    // 将查询任务委托给MyBatis 的执行器 Executor
    List<E> result = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    var6 = result;
    } catch (Exception var10) {
    throw ExceptionFactory.wrapException("Error querying database. Cause: " + var10, var10);
    } finally {
    ErrorContext.instance().reset();
    }

    return var6;
    }

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    // 根据具体传入的参数,动态地生成需要执行的SQL语句,用BoundSql对象表示
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    // 为当前的查询创建一个缓存Key
    CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
    // 再进去
    return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    // 获得缓存对象
    Cache cache = ms.getCache();
    if(cache != null) {
    this.flushCacheIfRequired(ms);
    if(ms.isUseCache() && resultHandler == null) {
    this.ensureNoOutParams(ms, parameterObject, boundSql);
    // 如果缓存中有查询结果,则返回查询结果
    List<E> list = (List)this.tcm.getObject(cache, key);
    if(list == null) {
    // 如果缓存中没有查询结果则查询数据库
    list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    // 将查询结果放入缓存中
    this.tcm.putObject(cache, key, list);
    }
    return list;
    }
    }
    // 如果没有缓存对象则查询数据库(进入这里)
    return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, 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());
    if(this.closed) {
    throw new ExecutorException("Executor was closed.");
    } else {
    if(this.queryStack == 0 && ms.isFlushCacheRequired()) {
    this.clearLocalCache();
    }
    List list;
    try {
    ++this.queryStack;
    list = resultHandler == null?(List)this.localCache.getObject(key):null;
    if(list != null) {
    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
    } else {
    // 缓存中没有值,直接从数据库中读取数据(进入这里)
    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
    } finally {
    --this.queryStack;
    }
    return list;
    }
    }

    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
    List list;
    try {
    // 执行查询返回List 结果(进入这里)
    list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
    // 清楚之前的缓存
    this.localCache.removeObject(key);
    }
    // 将查询的结果放入缓存之中
    this.localCache.putObject(key, list);
    if(ms.getStatementType() == StatementType.CALLABLE) {
    this.localOutputParameterCache.putObject(key, parameter);
    }
    return list;
    }

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    List var9;
    try {
    Configuration configuration = ms.getConfiguration();
    // 创建StatementHandler对象来执行查询操作
    StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    // 利用StatementHandler对象创建java.Sql.Statement对象(进入这里)
    stmt = this.prepareStatement(handler, ms.getStatementLog());
    // 调用StatementHandler.query()方法,返回List结果集 (进入这里)
    var9 = handler.query(stmt, resultHandler);
    } finally {
    this.closeStatement(stmt);
    }
    return var9;
    }

    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    // 创建连接
    Connection connection = this.getConnection(statementLog);
    // 创建java.Sql.Statement对象,传递给StatementHandler对象
    Statement stmt = handler.prepare(connection);
    // 对创建的Statement对象设置参数,即设置SQL语句中占位符设置为指定的参数
    handler.parameterize(stmt);
    return stmt;
    }

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    // 调用preparedStatemnt的execute()方法,然后将resultSet交给ResultSetHandler处理
    PreparedStatement ps = (PreparedStatement)statement;
    ps.execute();
    // 使用ResultHandler来处理ResultSet(进入这里)
    return this.resultSetHandler.handleResultSets(ps);
    }
  5. 终于查询完了,现在可以处理结果了,我们看看handleResultSets(Statement stmt)方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
    // 最后的结果集
    List<Object> multipleResults = new ArrayList();
    int resultSetCount = 0;
    ResultSetWrapper rsw = this.getFirstResultSet(stmt);
    List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    this.validateResultMapsCount(rsw, resultMapCount);

    while(rsw != null && resultMapCount > resultSetCount) {
    // 获得resultMap
    ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
    // 这里才开始处理(这里自己去看吧,反正会先处理行值,然后映射成对象,和JDBC一样)
    this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
    rsw = this.getNextResultSet(stmt);
    this.cleanUpAfterHandlingResultSet();
    ++resultSetCount;
    }

    String[] resultSets = this.mappedStatement.getResulSets();
    if(resultSets != null) {
    while(rsw != null && resultSetCount < resultSets.length) {
    ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
    if(parentMapping != null) {
    String nestedResultMapId = parentMapping.getNestedResultMapId();
    ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
    this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
    }

    rsw = this.getNextResultSet(stmt);
    this.cleanUpAfterHandlingResultSet();
    ++resultSetCount;
    }
    }

    return this.collapseSingleResultList(multipleResults);
    }

参考

  1. 终结篇:MyBatis原理深入解析(一)
  2. MyBatis源码解析(二)——动态代理实现函数调用