Mybatis源码解读系列(四)-StatementHandler

260 阅读6分钟

这一篇我们来梳理Mybatis中的StatementHandler接口及其对应的实现类。

这个接口处理的是java JDBC对应的Statement,可以先搜索其他博文复习下关于JDBC的内容

一、StatementHandler的结构

public interface StatementHandler {

  Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;
  void parameterize(Statement statement)
      throws SQLException;
  void batch(Statement statement)
      throws SQLException;
  int update(Statement statement)
      throws SQLException;
  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;
  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;
  BoundSql getBoundSql();
  ParameterHandler getParameterHandler();

}

可以看到这里抽象定义了对Statement一些操作的方法。

2、方法

1)、prepare(Connection connection, Integer transactionTimeout)

​ 这个方法就是通过sql连接及对应的事务超时时间创建对应的JDB语句处理的Statement对象。

2、parameterize(Statement statement)

​ 对入参进行对应的处理

3、batch(Statement statement)

​ 批量操作接口。

4、update(Statement statement)

​ 更新操作。

5、query(Statement statement, ResultHandler resultHandler)

​ 查询接口,这里的其中一个入参ResultHandler 是表明用来处理查询结果的。

6、queryCursor(Statement statement)

​ 这个接口是用来处理调用处理存储过程的,我们之后也会忽略关于存储过程的一些细节内容。

7、getBoundSql()

​ 这个是获取BoundSql,这个BoundSql是与sql语句执行的一些内容,前面文章有介绍。

8、getParameterHandler()

​ 获取参数处理器。

下面我们来看下StatementHandler的实现类。

二、BaseStatementHandler

1、结构

public abstract class BaseStatementHandler implements StatementHandler {

​ 这个是StatementHandler接口实现的基类,可以看到其只是简单的实现了StatementHandler接口。

2、成员变量

1)、configuration

protected final Configuration configuration;

​ 这个类我们在前面文章有梳理,其包含了整个Mybatis中加载的内容,有点类似于Spring容器中存放对象的类 DefaultListableBeanFactory。

2)、objectFactory

protected final ObjectFactory objectFactory;

​ 创建对象的工厂。

3)、typeHandlerRegistry

protected final TypeHandlerRegistry typeHandlerRegistry;

​ 类型转换处理器,在前面文章也有对应的分析,例如可以通过在xml写的类型例如javaType,jdbcType来处理对应的值。

4)、resultSetHandler

protected final ResultSetHandler resultSetHandler;
public interface ResultSetHandler {

  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;
}

​ 结构集处理器,用来处理执行查询语句后的ResultSet内容的。

5)、parameterHandler

protected final ParameterHandler parameterHandler;
public interface ParameterHandler {

  Object getParameterObject();
  void setParameters(PreparedStatement ps)
      throws SQLException;
}

​ 参数处理器,用来设置获取对应参数的。

6)、executor

protected final Executor executor;

​ 执行器,这个我们之后再梳理这个接口及其实现。

7)、mappedStatement

protected final MappedStatement mappedStatement;

​ 这个类我们前面也有了解,其包含Mapper接口中方法执行相关的内容。例如用来查询方法,这个MappedStatement就包含要执行这个方法的内容,例如sql、执行类型等各种信息。

8)、rowBounds

protected final RowBounds rowBounds;
public class RowBounds {

  public static final int NO_ROW_OFFSET = 0;
  public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
  public static final RowBounds DEFAULT = new RowBounds();

​ 分页用的,例如limit NO_ROW_OFFSET NO_ROW_LIMIT。

​ 9)、boundSql

protected BoundSql boundSql;

​ sql语句相关内容。

​ 3、构造方法

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);
}

​ 这个就是创建时候对对应变量的初始化赋值。

​ 1)、newParameterHandler(...)

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
  ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
  parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
  return parameterHandler;
}
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
 }

​ 可以看到ParameterHandler是直接使用的默认参数处理器DefaultParameterHandler。但这里需要注意的是,在DefaultParameterHandler创建后,还会将其去执行Interceptor(所以就可以在这里去进行对应的拓展,例如去实现Interceptor接口创建一个自定义的ParameterHandler)。

​ 2)、 newResultSetHandler(...)

public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
    ResultHandler resultHandler, BoundSql boundSql) {
  ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
  resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
  return resultSetHandler;
}

​ 这个一前面类似,也是使用的默认结果集处理器DefaultResultSetHandler,然后也会执行pluginAll方法。

3、主要方法

1)、prepare(Connection connection, Integer transactionTimeout)

@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);
    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);
  }
}
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

​ 创建Statement,再设置其的超时时间、fetchSize。不过这里的创建Statement是一个抽象方法需要其的子类实现。

三、SimpleStatementHandler

这个就是简单语句处理器,基于Statement去操作。

1、结构&构造方法

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

​ 继于BaseStatementHandler,然后构造方法直接调用的父类BaseStatementHandler。

2、方法

1)、update(Statement statement)

@Override
public int update(Statement statement) throws SQLException {
  String sql = boundSql.getSql();
  Object parameterObject = boundSql.getParameterObject();
  KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
  int rows;
  if (keyGenerator instanceof Jdbc3KeyGenerator) {
    statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
    rows = statement.getUpdateCount();
    keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
  } else if (keyGenerator instanceof SelectKeyGenerator) {
    statement.execute(sql);
    rows = statement.getUpdateCount();
    keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
  } else {
    statement.execute(sql);
    rows = statement.getUpdateCount();
  }
  return rows;
}

​ 这个就是执行对应的更新sql,我们忽略这里与keyGenerator相关的内容,其主要是两条语句,通过statement.execute(sql)执行对应的sql,然后在通过getUpdateCount方法获取本次受影响的行数再返回。

2)、batch(Statement statement)

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

​ 批处理方法,直接调用的statement.addBatch(sql)。

3)、query(Statement statement, ResultHandler resultHandler)

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

​ 查询方法,其会通过ResultHandler去处理对应的ResultSet结果集。

4)、queryCursor(Statement statement)

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

​ 这个是处理存储过程。

5)、instantiateStatement(Connection connection)

@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);
  }
}

​ 可以看到这里对Statement创建是不同的,如果是ResultSetType.DEFAULT,则直接创建。但如果是其他的,其会再这里设置对应的结果集遍历对应的操作。

6)、parameterize(Statement statement)

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

​ 没有操作。

四、PreparedStatementHandler

​ 这个StatementHandler是基于PreparedStatement去进行对应的操作

1、结构&构造方法

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);
  }

​ 与前面的SimpleStatementHandler一样。

2、方法

1)、update(Statement statement)

@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;
}

​ 这里也是ps.execute()、ps.getUpdateCount()的执行,不过不同点是这里使用的PreparedStatement。

2)、batch(Statement statement)

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

3)、query(Statement statement, ResultHandler resultHandler)

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

​ 查询再通过ResultHandler去处理对应的结果。

4)、queryCursor(Statement statement)

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

​ 存储过程相关执行。

5)、instantiateStatement(Connection connection)

@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() == ResultSetType.DEFAULT) {
    return connection.prepareStatement(sql);
  } else {
    return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  }
}

​ 这里就是创建PrepareStatement,以及设置对应的结果遍历的行为。

6)、parameterize(Statement statement)

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

​ 这里与前面SimpleStatementHandler不同的是其会去调用parameterHandler.setParameters((PreparedStatement) statement)去设置对应参数。