程序员Mybatis源码之路

StatementHandler

2020-08-30  本文已影响0人  93张先生

StatementHandler

StatementHandler 依赖 ParameterHandler 和 ResultSetHandler
完成了 Mybatis 的核心功能,它控制着参数绑定、 SQL 语句执行、结果集映射等一系列核心过程。

StatementHandler 是一个接口,定义了一些规范,有四个实现类,定义了具体的实现。

public interface StatementHandler {

// 从连接中获取一个 Statement
Statement prepare(Connection connection, Integer transactionTimeout)
    throws SQLException;
// 绑定 statement 执行时所需的实参
void parameterize(Statement statement)
    throws SQLException;
// 批量执行 SQL 语句
void batch(Statement statement)
    throws SQLException;
// 执行 update/insert/delete 语句
int update(Statement statement)
    throws SQLException;
// 执行 select 语句
<E> List<E> query(Statement statement, ResultHandler resultHandler)
    throws SQLException;
// 执行 select 语句
<E> Cursor<E> queryCursor(Statement statement)
    throws SQLException;

BoundSql getBoundSql();
// 获取 ParameterHandler 对象
ParameterHandler getParameterHandler();

}
UML 类图
image.png

RoutingStatementHandler

RoutingStatementHandler 会根据 MappedStatement 指定的 statementType 宇段,创建对应的 StatementHandler 接口实现。
定义一个 StatementHandler 接口 代理对象,根据 statementType 类型,创建 StatementHandler 接口具体实现,有点像策略模式。

public class RoutingStatementHandler implements StatementHandler {

  private final StatementHandler delegate;

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        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());
    }

  }
}

BaseStatementHandler

BaseStatementHandler 是 StatementHandler 的一个抽象类定义了各个 StatementHandler 接口集体实现的公共成员。

public abstract class BaseStatementHandler implements StatementHandler {

  protected final Configuration configuration;
  // 对象工厂,创建对象来使用
  protected final ObjectFactory objectFactory;
  // 类型转换注册器
  protected final TypeHandlerRegistry typeHandlerRegistry;
  // SQL 查询结果,封装成 ResultMap 对象 处理器
  protected final ResultSetHandler resultSetHandler;
  // 记录使用的 ParameterHandler 对象, ParameterHandler 的主要功能是为 SQL 句绑定实参 ,使用实参替换 SQL 吾句的中 ? 占位符。
  protected final ParameterHandler parameterHandler;

  // sql 执行器
  protected final Executor executor;
  // 封装 mapper.xml <SQL> 节点 成 MappedStatement 对象
  protected final MappedStatement mappedStatement;
  //  RowBounds 记录了用户设置的 offset limit ,用于在结采集中定位映射的起始位置和结束位置
  protected final RowBounds rowBounds;

  // 数据库可以执行的 SQL 语句
  protected BoundSql boundSql;

  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
      // 调用 KeyGenerator processBefore() 方法获取主键
      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);
  }
}

SimpleStatementHandler

SimpleStatementHandler 继承了 BaseStatementHandler 抽象类。它底层使用 java.sql.Statement 对象来完成数据库的相关操作。所以 SQL 语句中不能存在占位符,相应的,SimpleStatementHandler.parameterize() 方法是空实现。


  public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  @Override
  public int update(Statement statement) throws SQLException {
    //获取 SQL 语句
    String sql = boundSql.getSql();
    //获取用户传入的实参
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    int rows;
    if (keyGenerator instanceof Jdbc3KeyGenerator) {
      // 执行 SQL 语句
      statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
      // 获取受影响的行数
      rows = statement.getUpdateCount();
      // 将数据库生成的主键添加到 parameterObject 中
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else if (keyGenerator instanceof SelectKeyGenerator) {
      statement.execute(sql);
      rows = statement.getUpdateCount();
      // 执行 <selectKey> 节点中配置的 SQL 语句获取数据库生成的主键,并添加到 parameterObject 中
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else {
      // update、delete 语句
      statement.execute(sql);
      rows = statement.getUpdateCount();
    }
    return rows;
  }

  @Override
  public void batch(Statement statement) throws SQLException {
    String sql = boundSql.getSql();
    statement.addBatch(sql);
  }

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    // 获取 SQL 语句
    String sql = boundSql.getSql();
    // 调用 Statement.executor()方法执行 SQL 语句
    statement.execute(sql);
    // 映射结果集
    return resultSetHandler.handleResultSets(statement);
  }

  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.handleCursorResultSets(statement);
  }

  /**
   * instantiateStatement 方法直接通过 JDB Connection 创建 statement 对象
   * @param connection
   * @return
   * @throws SQLException
   */
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      return connection.createStatement();
    } else {
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

  @Override
  public void parameterize(Statement statement) {
    // N/A
  }

}

PreparedStatementHandler

PreparedStatementHandler 底层依赖于 java.sq1.PreparedStatement 象来完成数据库的相关操。
在 SimpleStatementHandler.parameterize() 方法中, 会调用前面介绍的 ParameterHandler.setParameters() 方法完成 SQL 语句的参数绑定。

public class PreparedStatementHandler extends BaseStatementHandler {

  public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  @Override
  public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
  }

  @Override
  public void batch(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.addBatch();
  }

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

  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.handleCursorResultSets(ps);
  }

  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    //获取待执行的 SQL 语句
    String sql = boundSql.getSql();
    //根据 MappedStatement.keyGenerator 字段的位,创建 PreparedStatement 对象
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); // 返回数据库生成的主键
      } else {
        // 在 insert 语句执行完成之后,会将 keyColumn 指定的列对象
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      //创建普通的 PreparedStatement 对象
      return connection.prepareStatement(sql);
    } else {
      //设置结果集是否可以滚动以及其游标是否可以上下移动,设置结采集是否可更新
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

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

}

CallableStatementHandler

CallableStatementHndler 底层依赖于 java.sql.CallableStatement 调用存储过程,其中 parameterize()方法也会调用 ParameterHandler.setParameters()方法完 SQL 语句参数绑定,并指定输出参数的索引位置和 JDBC 类型。

public class CallableStatementHandler extends BaseStatementHandler {

  public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  @Override
  public int update(Statement statement) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.execute();
    int rows = cs.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
    resultSetHandler.handleOutputParameters(cs);
    return rows;
  }

  @Override
  public void batch(Statement statement) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.addBatch();
  }

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

  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    CallableStatement cs = (CallableStatement) statement;
    cs.execute();
    Cursor<E> resultList = resultSetHandler.handleCursorResultSets(cs);
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      return connection.prepareCall(sql);
    } else {
      return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

  @Override
  public void parameterize(Statement statement) throws SQLException {
    registerOutputParameters((CallableStatement) statement);
    parameterHandler.setParameters((CallableStatement) statement);
  }
    /**
   * 处理存储过程中的参数类型
   * @param cs
   * @throws SQLException
   */
  private void registerOutputParameters(CallableStatement cs) throws SQLException {
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    for (int i = 0, n = parameterMappings.size(); i < n; i++) {
      ParameterMapping parameterMapping = parameterMappings.get(i);
      if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
        if (null == parameterMapping.getJdbcType()) {
          throw new ExecutorException("The JDBC Type must be specified for output parameter.  Parameter: " + parameterMapping.getProperty());
        } else {
          if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
            cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
          } else {
            if (parameterMapping.getJdbcTypeName() == null) {
              cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
            } else {
              cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
            }
          }
        }
      }
    }
  }

}

上一篇 下一篇

猜你喜欢

热点阅读