Mybatis源码(五)

6、SimpleExecutor.doQuery()

1)创建StatementHandler

在 configuration.newStatementHandler()中,new一个newStatementHandler,先得到RoutingStatementHandler。

RoutingStatementHandler里面没有任何的实现,使用来创建基本的StatementHandler的。这里会根据MappedStatement里面的getStatementType
决定StatementHandler的类型。默认是PREPARED(STATEMENT、PREPARED、CALLABLE)

  switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        // 创建 StatementHandler 的时候做了什么? >>
        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());
    }

StatementHandler里面包含了处理参数的ParameterHandler和处理结果集的ResultSetHandler。

这两个对象创建:

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, 
RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    ....

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, 
parameterHandler, resultHandler, boundSql);
}

这三个对象都可以被插件拦截的,所以在创建之后都要用拦截器进行包装方法。

// 植入插件逻辑(返回代理对象)
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);

resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);

statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);

四大对象包装创建完成。

QA:上面是三个对象,还有一个对象?是在什么时候创建的?(Executor)

  1. 创建Statement

用new出来的statementHandler创建statement对象。

如果有插件包装,会先走到被拦截的业务逻辑,SimpleExecutor对象

// 获取一个 Statement对象
stmt = prepareStatement(handler, ms.getStatementLog());

prepareStatement方法对语句执行,处理参数:

// 执行查询
handler.query(stmt, resultHandler);

这里会调用parameterHandler设置参数,如果有插件包装,会先走到被拦截的业务逻辑。

@Override
public void parameterize(Statement statement) throws SQLException {
    parameterHandler.setParameters((PreparedStatement) statement);
}

执行StatementHandler的query方法。

RoutingStatementHandler的query()方法。

delegate委派,最终执行PreparedStatementHandler的query()方法。

4)执行PreparedStatement的execute方法

// 到了JDBC的流程
ps.execute();

后面就是JDBC的PreparedStatement的执行了。

5)resultSetHandler处理结果集

如果有插件包装,会先走到被拦截的业务逻辑。

// 处理结果集
return resultSetHandler.handleResultSets(ps);
QA:怎么把ResultSet转换成List<Object>的呢?

    resultSetHandler只有一个实现类:DefaultResultSetHandler。也就是执行了DefaultResultSetHandler的handleResultSets()方法。
首先我们会先拿到第一个结果集,如果没有配置一个查询返回多个结果集的情况,一般只有一个结果集。如果下面的这个while循环我们不使用,
就是执行一次。
然后调用handleResultSet()方法。
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ...

    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++;
    }
    ...
        if (parentMapping != null) {
            ...
                handleResultSet(rsw, resultMap, null, parentMapping);
        }
}

调用代理方法,执行SQL

image

posted @ 2020-07-06 15:02  snail灬  阅读(108)  评论(0编辑  收藏  举报