大懒使小懒之StatementHandler

大懒使小懒之StatementHandler

前一节咱们已经在看到了sql执行的背后高手Executor(说是高手其实就是SqlSession的高级员工),术业有专攻,当领导任务下达给Executor以后,Executor制定大致的行动方向,接下来就把一切具体的实现交给了本身的小弟StatementHandler,真是名副其实的大懒使小懒呀!java

首先让咱们来看看StatementHandler中都有谁。sql

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

}

根据jdbc中不一样的statement,核心的三个子类:app

一、SimpleStatementHandler:用于处理Statement数据库操做ide

二、PreparedStatementHandler:用于处理PreparedStatement数据库操做函数

三、CallableStatementHandler:用于处理CallableStatement数据库操做.net

他们三个都继承自同一个基类BaseStatementHandler,让咱们来看看这个类设计

BaseStatementHandler 对StatementHandler接口的方法进行了实现,其中只有一个抽象方法交由子类进行实现3d

protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

根据方法名,咱们能够大概知道这个方法是不一样子类实例化不一样statement的方法。咱们逐一来看一下。code

/**
* SimpleStatementHandler
**/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
  //mapper 中未指定结果集类型,直接建立Statement对象
  if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
    return connection.createStatement();
  } else {//根据所给定的结果集类型,建立Statement对象
    return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  }
}

**注:**关于结果集类型可参考 jdbc ResultSetType 说明

/**
* PreparedStatementHandler
**/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
  //获得执行的Sql
  String sql = boundSql.getSql();
  //判断是否有主键生成器(insert语句须要)
  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);
    }
  //若是没有,而且ResultSetType是DEFAULT,根据SQL建立 prepareStatement对象
  } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
    return connection.prepareStatement(sql);
  } else {
    return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  }
}
/**
* CallableStatementHandler
**/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
   //获得执行的Sql
  String sql = boundSql.getSql();
  if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
    //若是ResultSetType是DEFAULT,根据SQL建立 prepareStatement对象
    return connection.prepareCall(sql);
  } else {
    return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  }
}

根据配置,经过instantiateStatement实例化完成相应的statement以后,接下来让咱们看看 StatementHandle是如何完成Executor给他的任务的。

不管是query 仍是 update,Executor只让它执行了两步任务,准备statement,执行statement。以doQuery为例咱们来看一看。

//准备statement 
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }

能够看出,在得到数据库链接以后,Handler经过执行prepare方法,建立好相应的statement。

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

惊不惊喜,意不意外,prepare方法其实就是执行了instantiateStatement方法,并设置了超时时间和每次获取数据的数量。

接下来就是进行参数的设置。不一样StatementHandler经过实现parameterize方法实现不一样的参数设置方式。

/*
** SimpleStatementHandler.parameterize(Statement statement)
** statement直接执行sql,所以不须要参数设置,此处为空
*/
@Override
public void parameterize(Statement statement) {
  // N/A
}

/*
** PreparedStatementHandler.parameterize(Statement statement)
** 委托parameterHandler进行参数设置
*/
 @Override
 public void parameterize(Statement statement) throws SQLException {
    parameterHandler.setParameters((PreparedStatement) statement);
 }

/*
** CallableStatementHandler.parameterize(Statement statement)
** 委托parameterHandler进行参数设置
*/
  @Override
  public void parameterize(Statement statement) throws SQLException {
    registerOutputParameters((CallableStatement) statement);
    parameterHandler.setParameters((CallableStatement) statement);
  }

ParameterHandler 有惟一的实现类DefaultParameterHandler,让咱们看看它是如何实现setParameters方法的。

@Override
public void setParameters(PreparedStatement ps) {
  ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  if (parameterMappings != null) {
    //循环参数列表
    for (int i = 0; i < parameterMappings.size(); i++) {
      ParameterMapping parameterMapping = parameterMappings.get(i);
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        String propertyName = parameterMapping.getProperty();
        if (boundSql.hasAdditionalParameter(propertyName)) { 
          value = boundSql.getAdditionalParameter(propertyName);
        } else if (parameterObject == null) {
          value = null;
        } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
          value = parameterObject;
        } else {
          MetaObject metaObject = configuration.newMetaObject(parameterObject);
          value = metaObject.getValue(propertyName);
        }
        TypeHandler typeHandler = parameterMapping.getTypeHandler();
        JdbcType jdbcType = parameterMapping.getJdbcType();
        if (value == null && jdbcType == null) {
          jdbcType = configuration.getJdbcTypeForNull();
        }
        try {
          // 委托typeHandler进行参数设置
          typeHandler.setParameter(ps, i + 1, value, jdbcType);
        } catch (TypeException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        } catch (SQLException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        }
      }
    }
  }
}

万事俱备,只欠东风。一个被安排的明明白白的statement,只须要在适当的时机执行execute() 方法,sql便执行了。至此在经历了Executor——>StatementHandler这两个委托者以后,sqlSession终于执行完成了一个SQL语句。PreparedStatementHandler.query()方法为例:

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  //执行sql
  ps.execute();
  //返回结果集
  return resultSetHandler.handleResultSets(ps);
}

关于RoutingStatementHandler

RoutingStatementHandler 做为 StatementHandler的实现类,却在实现是没有一丝一毫本身的实现逻辑,它更像是一个StatementHandler的策略选择器,根据Statement type 建立不一样的StatementHandler。全部方法的实现也都是调用相应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());
  }
}

至此,关于StatementHandler的介绍就基本上结束了。咱们已经大致上知道一个sql的执行流程:

SqlSession ——>Exeecutor ——>StatementHandler。

然而TypeHandler是如何set参数的?sql执行成功以后resultHandler是如何映射结果集的?这将是咱们接下来主要研究的内容。

相关文章
相关标签/搜索