前一节咱们已经在看到了sql执行的背后高手Executor(说是高手其实就是SqlSession的高级员工),术业有专攻,当领导任务下达给Executor以后,Executor制定大致的行动方向,接下来就把一切具体的实现交给了本身的小弟StatementHandler,真是名副其实的大懒使小懒呀!java
首先让咱们来看看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; <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 做为 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是如何映射结果集的?这将是咱们接下来主要研究的内容。