StatementHandler

fxz大约 12 分钟

StatementHandler

JDBC处理器,基于JDBC构建JDBC Statement,并设置参数,然后执行Sql。每调用会话当中一次SQl,都会有与之相对应的且唯一的Statement实例。使用 ParameterHandler 进行参数配置,使用 ResultSetHandler 把查询结果与实体类进行绑定

总共执行过程分为三个阶段:

  1. 预处理:这里预处理不仅仅是通过Connection创建Statement,还包括设置参数。
  2. 执行:包含执行SQL和处理结果映射两部分。
  3. 关闭:直接关闭Statement。
/**
 * Statement 处理器,其中 Statement 包含 java.sql.Statement、java.sql.PreparedStatement、java.sql.CallableStatement 三种。
 *
 * @author Clinton Begin
 */
public interface StatementHandler {

    /**
     * 准备操作,可以理解成创建 Statement 对象
     *
     * @param connection         Connection 对象
     * @param transactionTimeout 事务超时时间
     * @return Statement 对象
     */
    Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;

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

    /**
     * 添加 Statement 对象的批量操作
     *
     * @param statement Statement 对象
     */
    void batch(Statement statement) throws SQLException;

    /**
     * 执行写操作
     *
     * @param statement Statement 对象
     * @return 影响的条数
     */
    int update(Statement statement) throws SQLException;

    /**
     * 执行读操作
     *
     * @param statement     Statement 对象
     * @param resultHandler ResultHandler 对象,处理结果
     * @param <E>           泛型
     * @return 读取的结果
     */
    <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;

    /**
     * 执行读操作,返回 Cursor 对象
     *
     * @param statement Statement 对象
     * @param <E>       泛型
     * @return Cursor 对象
     */
    <E> Cursor<E> queryCursor(Statement statement) throws SQLException;

    /**
     * @return BoundSql 对象
     */
    BoundSql getBoundSql();

    /**
     * @return ParameterHandler 对象
     */
    ParameterHandler getParameterHandler();

}

RoutingStatementHandler 实现类,负责将不同的 Statement 类型,路由到上述三个实现类上

RoutingStatementHandler

实现 StatementHandler 接口,路由的 StatementHandler 对象,根据 Statement 类型,转发到对应的 StatementHandler 实现类中。

/**
 * 路由的 StatementHandler 对象,根据 Statement 类型,转发到对应的 StatementHandler 实现类中。
 *
 * @author Clinton Begin
 */
public class RoutingStatementHandler implements StatementHandler {

    /**
     * 被委托的 StatementHandler 对象
     */
    private final StatementHandler delegate;

    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 根据不同的类型,创建对应的 StatementHandler 实现类
        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());
        }
    }

    @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

/**
 * StatementHandler 基类,提供骨架方法,从而使子类只要实现指定的几个抽象方法即可
 *
 * @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;

    /**
     * 一次可执行的 SQL 封装
     */
    protected BoundSql boundSql;

    protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        // 获得 Configuration 对象
        this.configuration = mappedStatement.getConfiguration();

        this.executor = executor;
        this.mappedStatement = mappedStatement;
        this.rowBounds = rowBounds;

        // 获得 TypeHandlerRegistry 和 ObjectFactory 对象
        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        this.objectFactory = configuration.getObjectFactory();

        // 如果 boundSql 非空,一般是写类操作,例如:insert、update、delete ,则先获得自增主键,然后再创建 BoundSql 对象
        if (boundSql == null) { // issue #435, get the key before calculating the statement
            // 获得自增主键
            generateKeys(parameterObject);
            // 创建 BoundSql 对象
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }
        this.boundSql = boundSql;

        // 创建 ParameterHandler 对象
        this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
        // 创建 ResultSetHandler 对象
        this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
    }

    @Override
    public BoundSql getBoundSql() {
        return boundSql;
    }

    @Override
    public ParameterHandler getParameterHandler() {
        return parameterHandler;
    }

    @Override
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
            // 创建 Statement 对象
            statement = instantiateStatement(connection);
            // 设置超时时间
            setStatementTimeout(statement, transactionTimeout);
            // 设置 fetchSize
            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;

    // 设置超时时间
    protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
        // 获得 queryTimeout
        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);
    }

    // 设置 fetchSize
    protected void setFetchSize(Statement stmt) throws SQLException {
        // 获得 fetchSize 。非空,则进行设置
        Integer fetchSize = mappedStatement.getFetchSize();
        if (fetchSize != null) {
            stmt.setFetchSize(fetchSize);
            return;
        }
        // 获得 defaultFetchSize 。非空,则进行设置
        Integer defaultFetchSize = configuration.getDefaultFetchSize();
        if (defaultFetchSize != null) {
            stmt.setFetchSize(defaultFetchSize);
        }
    }

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

    /**
     * 获得自增主键
     *
     * @param parameter 参数对象
     */
    protected void generateKeys(Object parameter) {
        // 获得 KeyGenerator 对象
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        ErrorContext.instance().store();
        // 前置处理,创建自增编号到 parameter 中
        keyGenerator.processBefore(executor, mappedStatement, null, parameter);
        ErrorContext.instance().recall();
    }

}

SimpleStatementHandler

/**
 * {@link java.sql.Statement} 的 StatementHandler 实现类
 *
 * @author Clinton Begin
 */
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);
    }

    @Override
    public int update(Statement statement) throws SQLException {
        String sql = boundSql.getSql();
        Object parameterObject = boundSql.getParameterObject();
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        int rows;
        // 如果是 Jdbc3KeyGenerator 类型
        if (keyGenerator instanceof Jdbc3KeyGenerator) {
            // 执行写操作
            statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
            // 获得更新数量
            rows = statement.getUpdateCount();
            // 执行 keyGenerator 的后置处理逻辑
            keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
            // 如果是 SelectKeyGenerator 类型
        } else if (keyGenerator instanceof SelectKeyGenerator) {
            // 执行写操作
            statement.execute(sql);
            // 获得更新数量
            rows = statement.getUpdateCount();
            // 执行 keyGenerator 的后置处理逻辑
            keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
        } else {
            // 执行写操作
            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 {
        String sql = boundSql.getSql();
        // 执行查询
        statement.execute(sql);
        // 处理返回结果
        return resultSetHandler.handleResultSets(statement);
    }

    @Override
    public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
        String sql = boundSql.getSql();
        // 执行查询
        statement.execute(sql);
        // 处理返回的 Cursor 结果
        return resultSetHandler.handleCursorResultSets(statement);
    }

    @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) throws SQLException {
        // N/A 因为无需做占位符参数的处理。
    }

}

PreparedStatementHandler

/**
 * {@link java.sql.PreparedStatement} 的 StatementHandler 实现类
 *
 * @author Clinton Begin
 */
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 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();
        // 处理返回的 Cursor 结果
        return resultSetHandler.handleCursorResultSets(ps);
    }

    @Override
    protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = boundSql.getSql();
        // 处理 Jdbc3KeyGenerator 的情况
        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);
        }
    }

    // Executor会调用StatementHandler的parameterize方法设置参数。
    @Override
    public void parameterize(Statement statement) throws SQLException {
        parameterHandler.setParameters((PreparedStatement) statement);
    }

}

我们已经看了各种 StatementHandler 的实现代码。那么,StatementHandler 对象究竟在 MyBatis 中,是如何被创建的呢?Configuration 类中,提供 #newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) 方法,代码如下:

// Configuration.java

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // <1> 创建 RoutingStatementHandler 对象
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    // 应用插件
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
}
  • <1> 处,创建 RoutingStatementHandler 对象。通过它,自动路由到适合的 StatementHandler 实现类。
  • <2> 处,应用插件。

StatementHandler 创建策略有三种。(默认为 PREPARED)

public enum StatementType {
  STATEMENT, PREPARED, CALLABLE
}

创建策略到底如何控制?可以在 Mapper.xml 内配置 statementType 属性。

<select id="findAllStudents" resultMap="StudentResult" statementType="STATEMENT">
	SELECT * FROM STUDENTS
</select>