zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    PHP写一段代码,确保多个进程同时写入一个文件成功
    PHP中的中文截取乱码问题_gb2312_utf-8
    TortoiseSVN使用详细步骤
    限制页面内部链接访问源-HTML注释
    Redis配置文件解读
    window下部署php_redis扩展
    js延迟加载,提升网页加载速度
    HTML5 LocalStorage 本地存储
    静态HTML页面不缓存js文件的方法
    寻找幸运数
  • 原文地址:https://www.cnblogs.com/snail-gao/p/13254836.html
Copyright © 2011-2022 走看看