MYBATIS-statement模块

img

概述

StatementHandler负责处理Mybatis与JDBC之间Statement的交互,而JDBC中的Statement,我们在学习JDBC的时候就了解过,就是负责与数据库进行交互的对象。这其中会涉及到一些对象,我们用到的时候再学习。首先,我们来看下StatementHandler的体系结构。

StatementHandler接口

statementHandler接口的实现大致有四个,其中三个实现类都是和JDBC中的Statement响对应的:

  1. SimpleStatementHandler,这个很简单了,就是对应我们JDBC中常用的Statement接口,用于简单SQL的处理;
  2. PreparedStatementHandler,这个对应JDBC中的PreparedStatement,预编译SQL的接口;
  3. CallableStatementHandler,这个对应JDBC中CallableStatement,用于执行存储过程相关的接口;
  4. RoutingStatementHandler,这个接口是以上三个接口的路由,没有实际操作,只是负责上面三个StatementHandler的创建及调用。
/**
 * @author Clinton Begin
 */
public interface StatementHandler {
  /**
   * 从connection中获取statement
   *
   * @param connection
   * @param transactionTimeout
   * @return
   * @throws SQLException
   */
  Statement prepare(Connection connection, Integer transactionTimeout)
    throws SQLException;

  /**
   * sql参数设置
   *
   * @param statement
   * @throws SQLException
   */
  void parameterize(Statement statement)
    throws SQLException;

  /**
   * 批量执行
   *
   * @param statement
   * @throws SQLException
   */
  void batch(Statement statement)
    throws SQLException;

  /**
   * 更新
   *
   * @param statement
   * @return
   * @throws SQLException
   */
  int update(Statement statement)
    throws SQLException;

  /**
   * 查询
   *
   * @param statement
   * @param resultHandler
   * @param <E>
   * @return
   * @throws SQLException
   */
  <E> List<E> query(Statement statement, ResultHandler resultHandler)
    throws SQLException;

  /**
   * 游标查询
   *
   * @param statement
   * @param <E>
   * @return
   * @throws SQLException
   */
  <E> Cursor<E> queryCursor(Statement statement)
    throws SQLException;

  /*
  获取BoundSql
   */
  BoundSql getBoundSql();

  /**
   * 获取参数处理器
   *
   * @return
   */
  ParameterHandler getParameterHandler();

}

RoutingStatementHandler

RoutingStatementHandler类似路由器,在其构造函数中会根据Mapper文件中设置的StatementType来选择使用SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler,其实现的接口StatementHandler的方法也是由这三个具体实现类来实现。


/**
 * 路由Statement处理器
 * 装饰器模式
 *
 * @author Clinton Begin
 */
public class RoutingStatementHandler implements StatementHandler {
  /**
   * 装饰器的StatementHandler
   */
  private final StatementHandler delegate;

  /**
   * 构造方法
   * 选择三种Statement,SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler
   *
   * @param executor
   * @param ms
   * @param parameter
   * @param rowBounds
   * @param resultHandler
   * @param boundSql
   */
  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //根据Statement类型选择不同的处理器
    switch (ms.getStatementType()) {
      //STATEMENT类型
      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());
    }

  }

  /**
   * 执行具体类型prepare
   *
   * @param connection
   * @param transactionTimeout
   * @return
   * @throws SQLException
   */
  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    return delegate.prepare(connection, transactionTimeout);
  }

  @Override
  public void parameterize(Statement statement) throws SQLException {
    delegate.parameterize(statement);
  }

  @Override
  public void batch(Statement statement) throws SQLException {
    delegate.batch(statement);
  }

  @Override
  public int update(Statement statement) throws SQLException {
    return delegate.update(statement);
  }

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    return delegate.query(statement, resultHandler);
  }

  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    return delegate.queryCursor(statement);
  }

  @Override
  public BoundSql getBoundSql() {
    return delegate.getBoundSql();
  }

  @Override
  public ParameterHandler getParameterHandler() {
    return delegate.getParameterHandler();
  }
}

BaseStatementHandler类

BaseStatementHandler是一个抽象类,并没有实现和CURD相关的类,只是更多的设置了一些参数相关。

/**
 * @author Clinton Begin
 */
public abstract class BaseStatementHandler implements StatementHandler {
  //配置信息
  protected final Configuration configuration;
  //对象工厂
  protected final ObjectFactory objectFactory;
  //类型处理器注册
  protected final TypeHandlerRegistry typeHandlerRegistry;
  //结果集处理
  protected final ResultSetHandler resultSetHandler;
  //参数处理器
  protected final ParameterHandler parameterHandler;
  //执行器
  protected final Executor executor;
  protected final MappedStatement mappedStatement;
  protected final RowBounds rowBounds;

  protected BoundSql boundSql;

  /**
   * 构造方法
   *
   * @param executor
   * @param mappedStatement
   * @param parameterObject
   * @param rowBounds
   * @param resultHandler
   * @param 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();
    //处理sql之前生成key
    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);
  }

  /**
   * 获取boundSql
   *
   * @return
   */
  @Override
  public BoundSql getBoundSql() {
    return boundSql;
  }

  /**
   * 获取参数处理器
   *
   * @return
   */
  @Override
  public ParameterHandler getParameterHandler() {
    return parameterHandler;
  }

  /**
   * 从连接中获取Statement对象
   *
   * @param connection
   * @param transactionTimeout
   * @return
   * @throws SQLException
   */
  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      statement = instantiateStatement(connection);
      //设置超时时间
      setStatementTimeout(statement, transactionTimeout);
      //设置读取条数,其实就是调用Statement.setFetchSize
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }

  /**
   * 如何实例化Statement,交给子类去做
   * @param connection
   * @return
   * @throws SQLException
   */
  protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

  /**
   *  设置超时,实际就是调用Statement.setQueryTimeout
   *
   * @param stmt
   * @param transactionTimeout
   * @throws SQLException
   */
  protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
    Integer queryTimeout = null;
    if (mappedStatement.getTimeout() != null) {
      queryTimeout = mappedStatement.getTimeout();
    } else if (configuration.getDefaultStatementTimeout() != null) {
      queryTimeout = configuration.getDefaultStatementTimeout();
    }
    if (queryTimeout != null) {
      stmt.setQueryTimeout(queryTimeout);
    }
    StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
  }

  /**
   * 设置读取条数,其实就是调用Statement.setFetchSize
   *
   * @param stmt
   * @throws SQLException
   */
  protected void setFetchSize(Statement stmt) throws SQLException {
    Integer fetchSize = mappedStatement.getFetchSize();
    if (fetchSize != null) {
      stmt.setFetchSize(fetchSize);
      return;
    }
    Integer defaultFetchSize = configuration.getDefaultFetchSize();
    if (defaultFetchSize != null) {
      stmt.setFetchSize(defaultFetchSize);
    }
  }

  /**
   * 关闭Statement
   *
   * @param statement
   */
  protected void closeStatement(Statement statement) {
    try {
      if (statement != null) {
        statement.close();
      }
    } catch (SQLException e) {
      //ignore
    }
  }

  /**
   * 生成主键
   *
   * @param parameter
   */
  protected void generateKeys(Object parameter) {
    //获取主键生成器
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    ErrorContext.instance().store();
    //生成主键
    keyGenerator.processBefore(executor, mappedStatement, null, parameter);
    ErrorContext.instance().recall();
  }
}

SimpleStatementHandler类

SimpleStatementHandler就是使用基本的Statement来执行query、batch、update等操作,其实现还是比较简单的,当然在执行过程中会涉及keyGenerator和ResultHandler操作。SimpleStatementHandler用于执行简单的sql语句,这里简单的sql语句是指sql语句中没有变量,不会通过外部进行参数传入的sql语句。


/**
 * 简单Statement处理器
 *
 * @author Clinton Begin
 */
public class SimpleStatementHandler extends BaseStatementHandler {
  /**
   * 构造方法
   *
   * @param executor
   * @param mappedStatement
   * @param parameter
   * @param rowBounds
   * @param resultHandler
   * @param boundSql
   */
  public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  /**
   * 更新操作
   *
   * @param statement
   * @return
   * @throws SQLException
   */
  @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();
      //获取执行后的主键
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else if (keyGenerator instanceof SelectKeyGenerator) {
      //执行sql
      statement.execute(sql);
      //获取执行行数
      rows = statement.getUpdateCount();
      //获取执行后的主键
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else {
      //如果没有keyGenerator,直接调用Statement.execute和Statement.getUpdateCount
      statement.execute(sql);
      rows = statement.getUpdateCount();
    }
    return rows;
  }

  /**
   * 批量sql执行
   *
   * @param statement
   * @throws SQLException
   */
  @Override
  public void batch(Statement statement) throws SQLException {
    //获取sql
    String sql = boundSql.getSql();
    //添加批处理sql
    statement.addBatch(sql);
  }

  /**
   * 查询
   * @param statement
   * @param resultHandler
   * @param <E>
   * @return
   * @throws SQLException
   */
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    //获取sql
    String sql = boundSql.getSql();
    //执行sql
    statement.execute(sql);
    //由结果处理器来处理结果
    return resultSetHandler.handleResultSets(statement);
  }

  /**
   * 游标查询
   * @param statement
   * @param <E>
   * @return
   * @throws SQLException
   */
  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    //获取sql
    String sql = boundSql.getSql();
    //执行sql
    statement.execute(sql);
    //由结果集处理器处理游标数据
    return resultSetHandler.handleCursorResultSets(statement);
  }

  /**
   * 实例化Statement实现
   * @param connection
   * @return
   * @throws SQLException
   */
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    //如果是默认的结果集
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      //直接创建Statement
      return connection.createStatement();
    } else {
      //其他情况创建具体类型的Statement
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

  /**
   * 简单处理器不处理参数
   * @param statement
   */
  @Override
  public void parameterize(Statement statement) {
    // N/A
  }

}

PreparedStatementHandler类

PreparedStatementHandler就是调用PreparedStatement来执行SQL语句,这样在第一次执行sql语句时会进行预编译,在接下来执行相同的SQL语句时会提高数据库性能

/**
 * 预处理Statement处理器
 *
 * @author Clinton Begin
 */
public class PreparedStatementHandler extends BaseStatementHandler {
  /**
   * 构造方法
   *
   * @param executor
   * @param mappedStatement
   * @param parameter
   * @param rowBounds
   * @param resultHandler
   * @param boundSql
   */
  public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  /**
   * 更新操作
   *
   * @param statement
   * @return
   * @throws SQLException
   */
  @Override
  public int update(Statement statement) throws SQLException {
    //转换成预编译的PreparedStatement
    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;
  }

  /**
   * 批量处理
   *
   * @param statement
   * @throws SQLException
   */
  @Override
  public void batch(Statement statement) throws SQLException {
    //转换成预编译的PreparedStatement
    PreparedStatement ps = (PreparedStatement) statement;
    //添加到批处理
    ps.addBatch();
  }

  /**
   * 查询操作
   *
   * @param statement
   * @param resultHandler
   * @param <E>
   * @return
   * @throws SQLException
   */
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    //转换成预编译的PreparedStatement
    PreparedStatement ps = (PreparedStatement) statement;
    //执行查询
    ps.execute();
    //交给结果集处理器处理
    return resultSetHandler.handleResultSets(ps);
  }

  //游标查询
  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    //转换成预编译的PreparedStatement
    PreparedStatement ps = (PreparedStatement) statement;
    //执行查询
    ps.execute();
    //交给结果集处理器处理
    return resultSetHandler.handleCursorResultSets(ps);
  }

  /**
   * 实例化Statement
   *
   * @param connection
   * @return
   * @throws SQLException
   */
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    //获取sql
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      //获取key的数组
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      //没有key就直接创建prepareStatement
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        //其他情况创建带有列明的prepareStatement
        return connection.prepareStatement(sql, keyColumnNames);
      }
      //如果结果集类型是默认的
    } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      //直接创建prepareStatement
      return connection.prepareStatement(sql);
    } else {
      //其他情况根据类型创建prepareStatement
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

  /**
   * 参数处理器处理参数
   *
   * @param statement
   * @throws SQLException
   */
  @Override
  public void parameterize(Statement statement) throws SQLException {
    parameterHandler.setParameters((PreparedStatement) statement);
  }

}

CallableStatementHandler

CallableStatementHandler实际就是使用CallableStatement来执行SQL语句,当然它执行的是存储过程。

/**
 * 存储过程处理器
 * @author Clinton Begin
 */
public class CallableStatementHandler extends BaseStatementHandler {
  /**
   * 构造方法
   * @param executor
   * @param mappedStatement
   * @param parameter
   * @param rowBounds
   * @param resultHandler
   * @param boundSql
   */
  public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  /**
   * 更新操作
   * @param statement
   * @return
   * @throws SQLException
   */
  @Override
  public int update(Statement statement) throws SQLException {
    //将statement转换为CallableStatement
    CallableStatement cs = (CallableStatement) statement;
    //执行execute操作
    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;
  }

  /**
   * 批量处理
   * @param statement
   * @throws SQLException
   */
  @Override
  public void batch(Statement statement) throws SQLException {
    //将statement转换为CallableStatement
    CallableStatement cs = (CallableStatement) statement;
    //添加到批处理
    cs.addBatch();
  }

  /**
   * 查询操作
   * @param statement
   * @param resultHandler
   * @param <E>
   * @return
   * @throws SQLException
   */
  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    //将statement转换为CallableStatement
    CallableStatement cs = (CallableStatement) statement;
    //执行查询
    cs.execute();
    //通过结果集处理器处理结果
    List<E> resultList = resultSetHandler.handleResultSets(cs);
    //处理参数
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

  /**
   * 游标查询
   * @param statement
   * @param <E>
   * @return
   * @throws SQLException
   */
  @Override
  public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
    //将statement转换为CallableStatement
    CallableStatement cs = (CallableStatement) statement;
    //执行execute操作
    cs.execute();
    //结果集处理器处理游标数据
    Cursor<E> resultList = resultSetHandler.handleCursorResultSets(cs);
    //处理输出参数
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

  /**
   * 实例化Statement
   * @param connection
   * @return
   * @throws SQLException
   */
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    //获取sql
    String sql = boundSql.getSql();
    //如果是默认的结果集处理器
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      //创建存储过程Statement
      return connection.prepareCall(sql);
    } else {
      //其他情况根据结果集类型创建存储过程Statement
      return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

  /**
   * 参数设置
   * @param statement
   * @throws SQLException
   */
  @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);
      //处理存储过程的INOUT和OUT
      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());
            }
          }
        }
      }
    }
  }

}