学习笔记之Mybatis源码(二)

    我们知道Mybatis中SqlSession的作用是完成一次数据库访问和结果映射,但是真正访问数据库的组件是SqlSession中的执行器Excutor。
    Excutor在我们使用SqlSessionFactory的openSession方法获取SqlSession时创建(由ExcutorType参数决定Excutor的类型)并注入到SqlSession中。ExcutorType参数的默认值是Simple,在开启Mybatis缓存的情况下默认使用CachingExcutor(CachingExcutor使用装饰器设计模式,只为ExcutorType类型的Excutor添加缓存的支持,所以我们重点看SimpleExcutor)。
    以查询为例,SimpleExcutor继承了BaseExcutor,所以我们查看BaseExcutor的query方法,代码如下:

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
 }

    根据代码可知,Excutor使用BoundSql生成SQL语句。继续跟下去会进入到doQuery方法。doQuery是抽象方法,所以我们去查看SimpleExcutor的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 handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }

    根据代码可知,Excutor在这里连接数据库并使用StatementHandle访问数据库(加载配置文件时设置了默认值,默认使用PrepareStatementHandle)。查看PrepareStatementHandle的初始化过程发现它使用父类的构造函数初始化。初始化代码如下:

  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;

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

    可以看到StatementHandle初始化时创建了ParameterHandler和ResultSetHandler,看名称可以知道大概是用于设置参数和处理结果映射。再查看ParameterHandler的query方法,代码如下:

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

    根据代码可知,在这里执行SQL语句,并且使用resultSetHandler把结果集映射到Java类。

总结
1.Excutor由SqlSessionFactory创建被注入到SqlSession。

2.Excutor使用BoundSql生成SQL语句。

3.Excutor使用StatementHandle执行Statement访问数据库。

4.Excutor使用ParameterHandle处理SQL语句的参数(没有深入ParameterHandle)。

5.Excutor使用ResultSetHandle处理结果集映射到Java类(没有深入研究ResultSetHandle)。

发布了4 篇原创文章 · 获赞 0 · 访问量 39

猜你喜欢

转载自blog.csdn.net/weixin_44247853/article/details/105178516