模板方法模式的应用之 MyBatis BaseStatementHandler

MyBatis StatementHandler 接口主要负责 SQL 语句的执行和参数的设置:

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;

  // ...

}

BaseStatementHandler 类是 StatementHandler 接口的抽象实现类,它定义了 StatementHandler 接口需要实现的大部分方法,包括对参数的设置、SQL 语句的执行等,并提供了一个抽象方法 instantiateStatement(Connection connection),供子类实例化 Statement 对象:

public abstract class BaseStatementHandler implements StatementHandler {
  // ...

  @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);
      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 对象(子类实现)
   */
  protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

  // ...
}

StatementHandler 的实现类 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler 分别对应不同的 Statement 对象,比如 SimpleStatementHandler 使用 Statement 对象执行 SQL 语句,PreparedStatementHandler 使用 PreparedStatement 对象执行 SQL 语句,CallableStatementHandler 使用 CallableStatement 对象执行 SQL 语句,它们都继承自 BaseStatementHandler 类,并实现了不同的 instantiateStatement() 方法,以 PreparedStatement 为例:

public class PreparedStatementHandler extends BaseStatementHandler {

  // ...

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

  // ...

}

可以看到,PreparedStatementHandler 通过调用 connection.prepareStatement() 方法实例化了一个 PreparedStatement 对象,并返回了该对象。

在这里,BaseStatementHandler 中的 prepare() 方法就是模板方法,其中定义了 prepare(准备)的通用步骤,instantiateStatement(实例化 Statement 对象)的细节交给子类实现。

posted @ 2025-02-18 23:27  Higurashi-kagome  阅读(13)  评论(0)    收藏  举报