Mybatis - StatementHandler 基础


介绍

StatementHandler 是四大组件中最重要的一个对象,一个 SQL 请求会经过会话,然后是执行器,最由 StatementHandler 执行 jdbc 最终到达数据库。

层次结构

SimpleStatementHandler

管理 Statement 对象并向数据库中推送不需要预编译的SQL语句。

PreparedStatementHandler

管理 Statement 对象并向数据中推送需要预编译的SQL语句。

CallableStatementHandler

管理 Statement 对象并调用数据库中的存储过程。

RoutingStatementHandler

在其构造函数中会根据 Mapper 文件中设置的 StatementType 来选择使用 SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler 作为内部的 delegate 对象。

PreparedStatementHandler 执行流程

预处理过程

当缓存都没有命中的情况下,BaseExecutor 会调用子类查询数据库的内容。

SimpleExecutor doQuery 方法

  public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, 
                               ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      // RoutingStatementHandler 对象,里面 delegate 对象是 PreparedStatementHandler 类型
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter,
                                                                rowBounds, resultHandler, boundSql);
      // JDBC4PreparedStatement 对象
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

  private Statement prepareStatement(StatementHandler handler, Log statementLog) {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection);
    handler.parameterize(stmt);
    return stmt;
  }

BaseStatementHandler prepare 方法

  public Statement prepare(Connection connection) throws SQLException {
    Statement statement = null;
    // 创建 statement
    statement = instantiateStatement(connection);
    setStatementTimeout(statement);
    setFetchSize(statement);
    return statement;
  }

PreparedStatementHandler instantiateStatement 方法

  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() != null) {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareStatement(sql);
    }
  }