Mybatis-StatementHandler源码解析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

StatementHandler

/**
 *    Copyright 2009-2016 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.statement;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.session.ResultHandler;

/**
 * StatementHandler负责处理Mybatis与JDBC之间Statement的交互,而JDBC中的Statement,就是负责与数据库进行交互的对象。
 * 

* 参考博客: *

https://www.jianshu.com/p/19686af69b0d *

* * @author Clinton Begin */ public interface StatementHandler { /** * 根据MappedStatement对象配置的StatementType,去创建Statement对象或则PreparedStatment或则CallableStatment * @param connection 数据库连接对象 * @param transactionTimeout 事务超时时间 */ Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException; /** * 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改 * @param statement 执行SQL 语句并返回它所生成结果的对象 */ void parameterize(Statement statement) throws SQLException; /** * 将 {@code statement} 添加到批处理队列 * @param statement 执行SQL 语句并返回它所生成结果的对象 */ void batch(Statement statement) throws SQLException; /** * 用于通知Statement将[insert,update,delete]推送到数据库 * @param statement 执行SQL 语句并返回它所生成结果的对象 * @return 更新记录数 */ int update(Statement statement) throws SQLException; /** * 用于通知Statement将[select]推送到数据库并返回对应查询结果 * @param statement 执行 SQL 语句并返回它所生成结果的对象 * @param resultHandler 结果处理器 * @param 结果对象类型 * @return 结果对象集合 */ List query(Statement statement, ResultHandler resultHandler) throws SQLException; /** * 用于通知Statement将[select]推送到数据库并返回对应游标结果 * @param statement 执行 SQL 语句并返回它所生成结果的对象 * @param 结果对象类型 * @return 结果对象游标对象 * @throws SQLException */ Cursor queryCursor(Statement statement) throws SQLException; /** * 获取参数映射与可执行SQL封装类对象 */ BoundSql getBoundSql(); /** * 获取参数处理器 */ ParameterHandler getParameterHandler(); }

RoutingStatementHandler

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.statement;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * 一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
 * @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) {

    //根据StatementType去新建对应的StatmentHandler对象,
    //ms.getStatementType默认是PREPARED
    switch (ms.getStatementType()) {
      case STATEMENT:
        //简单的Statement处理器,Statement:用于执行静态 SQL 语句并返回它所生成结果的对象
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        //PreparedStatement对象处理器,PreparedStatement: 预编译的 SQL 语句的对象
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        //CallableStatement对象处理器,CallableStatmement:用于执行 SQL 存储过程的接口实例
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        //没有配置StatementType的ms还怎么执行,肯定要抛出异常啦
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

  /**
   * 创建Statement对象或则PreparedStatment或则CallableStatment
   * @param connection 数据库连接对象
   * @param transactionTimeout 事务超时时间
   */
  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    //交由delegate处理
    return delegate.prepare(connection, transactionTimeout);
  }

  /**
   * 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改
   * @param statement 执行SQL 语句并返回它所生成结果的对象
   */
  @Override
  public void parameterize(Statement statement) throws SQLException {
    //交由delegate处理
    delegate.parameterize(statement);
  }

  /**
   * 将 {@code statement} 添加到批处理队列
   * @param statement 执行SQL 语句并返回它所生成结果的对象
   */
  @Override
  public void batch(Statement statement) throws SQLException {
    //交由delegate处理
    delegate.batch(statement);
  }

  /**
   * 用于通知Statement将[insert,update,delete]推送到数据库
   * @param statement 执行SQL 语句并返回它所生成结果的对象
   * @return 更新记录数
   */
  @Override
  public int update(Statement statement) throws SQLException {
    //交由delegate处理
    return delegate.update(statement);
  }

  /**
   * 用于通知Statement将[select]推送到数据库并返回对应查询结果
   * @param statement 执行 SQL 语句并返回它所生成结果的对象
   * @param resultHandler 结果处理器
   * @param  结果对象类型
   * @return 结果对象集合
   */
  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    //交由delegate处理
    return delegate.query(statement, resultHandler);
  }

  /**
   * 用于通知Statement将[select]推送到数据库并返回对应游标结果
   * @param statement 执行 SQL 语句并返回它所生成结果的对象
   * @param  结果对象类型
   * @return 结果对象游标对象
   * @throws SQLException
   */
  @Override
  public  Cursor queryCursor(Statement statement) throws SQLException {
    //交由delegate处理
    return delegate.queryCursor(statement);
  }

  /**
   * 获取参数映射与可执行SQL封装类对象
   */
  @Override
  public BoundSql getBoundSql() {
    //交由delegate处理
    return delegate.getBoundSql();
  }

  /**
   * 获取参数处理器
   */
  @Override
  public ParameterHandler getParameterHandler() {
    //交由delegate处理
    return delegate.getParameterHandler();
  }
}

BaseStatementHandler

/**
 *    Copyright 2009-2016 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.statement;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * 用于简化StatementHandler接口开发的难度,是适配器模式的体现,他有三个实现类:SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler。在RoutingStatementHandler创建时,就根据接受的Excutor来创建这三个类型对象。
 * @author Clinton Begin
 */
public abstract class BaseStatementHandler implements StatementHandler {

  /**
   * mybatis全局配置信息
   */
  protected final Configuration configuration;
  /**
   * 对象工厂
   */
  protected final ObjectFactory objectFactory;
  /**
   * 类型处理注册器,从mybatis全局配置信息中获取
   */
  protected final TypeHandlerRegistry typeHandlerRegistry;
  /**
   * 结果集处理器
   */
  protected final ResultSetHandler resultSetHandler;

  /**
   * 参数处理器
   */
  protected final ParameterHandler parameterHandler;

  /**
   * 执行器
   */
  protected final Executor executor;
  /**
   *  Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   */
  protected final MappedStatement mappedStatement;
  /**
   *  Mybatis的分页对象
   */
  protected final RowBounds rowBounds;
  /**
   * 参数映射与可执行SQL封装类对象
   */
  protected BoundSql boundSql;

  /**
   *
   * @param executor 执行器
   * @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameterObject 参数对象
   * @param rowBounds Mybatis的分页对象
   * @param resultHandler 结果处理器
   * @param boundSql 参数映射与可执行SQL封装类对象
   */
  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
      //调用mappedStatement配置的KeyGenerator,在executor执行boundSQL对象之前,生成Key赋值到parameter中
      generateKeys(parameterObject);
      //构建boundSQL
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;
    //构建参数处理器,默认情况下,构建的是DefaultParameteHandler实例
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    //构建结果集处理器,构建出来的是DefaultResultSetHandler实例
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }

  /**
   * 获取参数映射与可执行SQL封装类对象
   */
  @Override
  public BoundSql getBoundSql() {
    return boundSql;
  }

  /**
   * 获取参数处理器
   */
  @Override
  public ParameterHandler getParameterHandler() {
    return parameterHandler;
  }

  /**
   * 创建Statement对象或则PreparedStatment或则CallableStatment
   * @param connection 数据库连接对象
   * @param transactionTimeout 事务超时时间
   * @return 构建出来的Statement实例,已经配置了queryTimeout和fetchSize
   */
  @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    //设置错误日志上下文
    ErrorContext.instance().sql(boundSql.getSql());
    //定义一个Statement
    Statement statement = null;
    try {
      //实例化Statement
      statement = instantiateStatement(connection);
      //设置Statement超时时长
      setStatementTimeout(statement, transactionTimeout);
      //设置FetchSize:
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      //关闭Statment对象
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      //关闭Statment对象
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }

  /**
   * 实例化Statement对象
   * @param connection 数据库连接
   * @return Statement对象
   */
  protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

  /**
   * 设置Statement超时时长
   * @param stmt 执行SQL 语句并返回它所生成结果的对象。
   * @param transactionTimeout 事务超时时长
   */
  protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
    //定义查询超时时长变量名
    Integer queryTimeout = null;
    //如果有配置超时时长
    if (mappedStatement.getTimeout() != null) {
      //应用配置的超时时长
      queryTimeout = mappedStatement.getTimeout();

      //如果由配置全局的Statement超时时长
    } else if (configuration.getDefaultStatementTimeout() != null) {
      //应用全局配置的Statement超时时长
      queryTimeout = configuration.getDefaultStatementTimeout();
    }
    //如果queryTime不为null
    if (queryTimeout != null) {
      //将queryTime设置到Statement的
      stmt.setQueryTimeout(queryTimeout);
    }
    //应用事务超时。事务超时大于查询时间,则不做更改;否则将查询时间修改成事务时间
    StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
  }

  /**
   *
   * 设置FetchSize:
   * 

* 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动)。 *

*
*

* 假设fetchSize为5,查询总记录数为100,每批5次返回给你,最后结果还是总记录数,只是提高点查询的速度而已 *

*
*

* MySQL不支持fetchSize,默认为一次性取出所有数据。所以容易导致OOM, * 如果是Oracle的话就是默认取出fetchSize条数据。 * 裸露JDBC防止OOM可以调用statement的enableStreamingResults方法, * MyBatis应该在<select fetchSize="-2147483648">。 *

* @param stmt 执行SQL 语句并返回它所生成结果的对象。 */ protected void setFetchSize(Statement stmt) throws SQLException { //获取select标签的fetchSize属性 Integer fetchSize = mappedStatement.getFetchSize(); //如有设置fetchSize if (fetchSize != null) { //设置fetchSize到stmt stmt.setFetchSize(fetchSize); return; } //获取全局配置的FetchSize Integer defaultFetchSize = configuration.getDefaultFetchSize(); //如有设置fetchSize if (defaultFetchSize != null) { //设置fetchSize到stmt stmt.setFetchSize(defaultFetchSize); } } /** * 关闭Statment对象 * @param statement 执行SQL 语句并返回它所生成结果的对象 */ protected void closeStatement(Statement statement) { try { //如果statment不为null if (statement != null) { //关闭statment statement.close(); } } catch (SQLException e) { //ignore 忽略关闭时的异常 } } /** * 生成Key * @param parameter 参数对象 */ protected void generateKeys(Object parameter) { //获取配置的Key生成器 KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); //保存当前的上下文 ErrorContext.instance().store(); //在executor执行boundSQL对象之前,生成Key赋值到parameter中 keyGenerator.processBefore(executor, mappedStatement, null, parameter); //恢复当前上下文 ErrorContext.instance().recall(); } }

CallableStatementHandler

/**
 *    Copyright 2009-2018 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.statement;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.JdbcType;

/**
 * CallableStatement对象处理器,CallableStatmement:用于执行 SQL 存储过程的接口实例
 * @author Clinton Begin
 */
public class CallableStatementHandler extends BaseStatementHandler {

  /**
   *
   * @param executor 执行器
   * @param mappedStatement  Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameter 参数对象
   * @param rowBounds Mybatis的分页对象
   * @param resultHandler 结果处理器
   * @param boundSql 参数映射与可执行SQL封装类对象
   */
  public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  /**
   * 用于通知Statement将[insert,update,delete]推送到数据库
   * @param statement CallableStatement对象
   * @return 更新记录数
   * @throws SQLException
   */
  @Override
  public int update(Statement statement) throws SQLException {
    //将statement强转成CallableStatement对象
    CallableStatement cs = (CallableStatement) statement;
    //执行SQL
    cs.execute();
    //获取更新记录数
    int rows = cs.getUpdateCount();
    //获取参数对象
    Object parameterObject = boundSql.getParameterObject();
    //获取Key生成器
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    //执行Key生成器的业务逻辑,将结果赋值到参数对象对应属性中
    keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
    /**
     * 处理存储过程结果映射,将结果对象赋值到参数对象的属性中(这里的属性是指:参数属性映射配置里配置属性的ParameterType
     * 为ParameterMode.OUT或者ParameterMode.INOUT的属性)
     */
    resultSetHandler.handleOutputParameters(cs);
    return rows;
  }

  /**
   * 将 statement 添加到批处理队列
   * @param statement 执行SQL 语句并返回它所生成结果的对象
   * @throws SQLException
   */
  @Override
  public void batch(Statement statement) throws SQLException {
    //将statement强转成CallableStatement对象
    CallableStatement cs = (CallableStatement) statement;
    //添加到批量队列中
    cs.addBatch();
  }

  /**
   * 用于通知Statement将[select]推送到数据库并返回对应查询结果
   * @param statement CallableStatement对象
   * @param resultHandler 结果处理器
   * @param  结果对象类型
   * @return 结果对象集合
   */
  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    //将statement强转成CallableStatement对象
    CallableStatement cs = (CallableStatement) statement;
    //执行SQL
    cs.execute();
    //处理cs返回所有结果集,返回结果对象集合
    List resultList = resultSetHandler.handleResultSets(cs);
    /**
     * 处理存储过程结果映射,将结果对象赋值到参数对象的属性中(这里的属性是指:参数属性映射配置里配置属性的ParameterType
     * 为ParameterMode.OUT或者ParameterMode.INOUT的属性)
     */
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

  @Override
  public  Cursor queryCursor(Statement statement) throws SQLException {
    //将statement强转成CallableStatement对象
    CallableStatement cs = (CallableStatement) statement;
    //执行SQL
    cs.execute();
    //处理cs返回所有结果集,返回结果对象游标
    Cursor resultList = resultSetHandler.handleCursorResultSets(cs);
    /**
     * 处理存储过程结果映射,将结果对象赋值到参数对象的属性中(这里的属性是指:参数属性映射配置里配置属性的ParameterType
     * 为ParameterMode.OUT或者ParameterMode.INOUT的属性)
     */
    resultSetHandler.handleOutputParameters(cs);
    return resultList;
  }

  /**
   * 实例化Statement对象
   * @param connection 数据库连接
   * @return
   * @throws SQLException
   */
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    //获取可执行SQL
    String sql = boundSql.getSql();
    //mappedStatement对象配置的结果集类型为依赖驱动
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      //创建一个 CallableStatement 对象来调用数据库存储过程。
      return connection.prepareCall(sql);
    } else {
      /**
       * ResultSetType.FORWARD_ONLY:结果集的游标只能向下滚动
       * ResultSetType.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变
       * ResultSetType.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变
       *
       * ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。
       * ResultSet.CONCUR_UPDATABLE:能用结果集更新数据库中的表
       */
      //创建一个 CallableStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。
      return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

  /**
   * 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改
   * @param statement CallableStatement对象
   */
  @Override
  public void parameterize(Statement statement) throws SQLException {
    //注册输出参数到statement
    registerOutputParameters((CallableStatement) statement);
    //设置参数值到statement
    parameterHandler.setParameters((CallableStatement) statement);
  }

  /**
   * 注册输出参数到 {@code cs}
   * @param cs 用于执行 SQL 存储过程的接口实例
   */
  private void registerOutputParameters(CallableStatement cs) throws SQLException {
    //获取参数映射集合
    List parameterMappings = boundSql.getParameterMappings();
    //遍历参数映射集合
    for (int i = 0, n = parameterMappings.size(); i < n; i++) {
      //获取参数映射
      ParameterMapping parameterMapping = parameterMappings.get(i);
      //如果参数映射配置的模式为 输出参数 或者为 输入输出参数
      if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
        //如果参数映射配置jdbc类型为null
        if (null == parameterMapping.getJdbcType()) {
          //抛出异常
          throw new ExecutorException("The JDBC Type must be specified for output parameter.  Parameter: " + parameterMapping.getProperty());
        } else {
          //如果有配置小数点后保留的位数 且 配置的jdbc类型为JdbcType.NUMERIC 或者是 JdbcType.DECIMAL
          if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
            // 按顺序位置 parameterIndex 将参数注册,设置JDBC类型为JdbcType.NUMERIC 或者 JdbcType.DECIMAL,并设置其小数点后保留的位数
            cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
          } else {
            //如果没有配置jdbc类型名
            if (parameterMapping.getJdbcTypeName() == null) {
              // 按顺序位置 parameterIndex 将参数注册,设置jdbc类型为参数映射所配置的jdbc类型
              cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
            } else {
              // 按顺序位置 parameterIndex 将参数注册,设置jdbc类型为参数映射所配置的jdbc类型,并设置jdbc类型名
              cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
            }
          }
        }
      }
    }
  }

}

PreparedStatementHandler

/**
 *    Copyright 2009-2018 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.statement;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * PreparedStatement对象处理器,PreparedStatement: 预编译的 SQL 语句的对象
 * @author Clinton Begin
 */
public class PreparedStatementHandler extends BaseStatementHandler {

  /**
   *
   * @param executor 执行器
   * @param mappedStatement  Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameter 参数对象
   * @param rowBounds Mybatis分页对象
   * @param resultHandler 结果处理器
   * @param boundSql 参数映射与可执行SQL封装类对象
   */
  public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
  }

  /**
   * 用于通知Statement将[insert,update,delete]推送到数据库
   * @param statement PreparedStatement对象
   * @return 更新记录数
   * @throws SQLException
   */
  @Override
  public int update(Statement statement) throws SQLException {
    //将statement强转成PreparedStatment对象
    PreparedStatement ps = (PreparedStatement) statement;
    //执行SQL
    ps.execute();
    //获取更新记录数
    int rows = ps.getUpdateCount();
    //获取参数对象
    Object parameterObject = boundSql.getParameterObject();
    //获取Key生成器
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    //执行Key生成器的业务逻辑,将结果赋值到参数对象对应属性中
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
  }

  /**
   * 将{@code statment} 添加到批量队列中
   * 

* 参考文档:https://www.cnblogs.com/liqiu/p/3825544.html *

* @param statement PreparedStatement对象 * @throws SQLException */ @Override public void batch(Statement statement) throws SQLException { //将statement强转成PreparedStatement对象 PreparedStatement ps = (PreparedStatement) statement; //添加到批量队列中 ps.addBatch(); } /** * 用于通知Statement将[select]推送到数据库并返回对应查询结果 * @param statement PreparedStatement对象 * @param resultHandler 结果处理器 * @param 结果对象类型 * @return 结果对象集合 */ @Override public List query(Statement statement, ResultHandler resultHandler) throws SQLException { //将statement强转成PreparedStatement对象 PreparedStatement ps = (PreparedStatement) statement; //执行SQL ps.execute(); // 处理 ps 返回所有结果集,返回结果对象集合 return resultSetHandler.handleResultSets(ps); } /** * 用于通知Statement将[select]推送到数据库并返回对应游标结果 * @param statement PreparedStatement对象 * @param 结果对象类型 * @return 结果对象游标 */ @Override public Cursor queryCursor(Statement statement) throws SQLException { //将statement强转成PreparedStatement对象 PreparedStatement ps = (PreparedStatement) statement; //执行SQL ps.execute(); //处理stmt返回所有结果集,返回结果对象游标 return resultSetHandler.handleCursorResultSets(ps); } /** * 实例化Statement对象 * @param connection 数据库连接 * @return Statement对象 * @throws SQLException */ @Override protected Statement instantiateStatement(Connection connection) throws SQLException { //获取可执行的SQL String sql = boundSql.getSql(); //如果Key生成器是Jdbc3KeyGenerator实例 if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { //获取配置的列名 String[] keyColumnNames = mappedStatement.getKeyColumns(); //如果配置的列名为null if (keyColumnNames == null) { /** * PreparedStatement.RETURN_GENERATED_KEYS:使用的是INSERT语句时,可以取出新插入数据行中自动增长的列的值 * PreparedStatement.NO_GENERATED_KEYS:不会取出新插入数据行中自动增长的列的值 */ //创建一个默认 PreparedStatement 对象,该对象能获取自动生成的键 return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); } else { //创建一个能返回由keyColumnNames指定的自动生成键的默认 PreparedStatement 对象 return connection.prepareStatement(sql, keyColumnNames); } //mappedStatement对象配置的结果集类型为依赖驱动 } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { //创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。 return connection.prepareStatement(sql); } else { /** * ResultSetType.FORWARD_ONLY:结果集的游标只能向下滚动 * ResultSetType.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变 * ResultSetType.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变 * * ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。 * ResultSet.CONCUR_UPDATABLE:能用结果集更新数据库中的表 */ //创建一个 PreparedStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。 return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } /** * 主要针对PreparedStatment或则CallableStatment关联预编译SQL语句中占位符进行修改 * @param statement PreparedStatement对象 */ @Override public void parameterize(Statement statement) throws SQLException { //将参数对象赋值到statement中 parameterHandler.setParameters((PreparedStatement) statement); } }

SimpleStatementHandler

/**
 *    Copyright 2009-2018 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.statement;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

/**
 * 简单的Statement处理器,Statement:用于执行静态 SQL 语句并返回它所生成结果的对象
 * @author Clinton Begin
 */
public class SimpleStatementHandler extends BaseStatementHandler {

  /**
   *
   * @param executor 执行器
   * @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameter 参数对象
   * @param rowBounds Mybatis的分页对象
   * @param resultHandler 结果处理器
   * @param boundSql 参数映射与可执行SQL封装类对象
   */
  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 {
    //获取SQL脚本
    String sql = boundSql.getSql();
    //获取参数对象
    Object parameterObject = boundSql.getParameterObject();
    //获取Key生成器
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    //已更新的函数
    int rows;
    if (keyGenerator instanceof Jdbc3KeyGenerator) {
      //PreparedStatement.RETURN_GENERATED_KEYS:获取刚刚插入自增ID值
      //执行SQL
      statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
      //获取更新记录数
      rows = statement.getUpdateCount();
      //Keys生成器将更新之后主键信息赋值到参数对象对应的属性中
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else if (keyGenerator instanceof SelectKeyGenerator) {
      //执行SQL
      statement.execute(sql);
      //获取更新记录数
      rows = statement.getUpdateCount();
      //Keys生成器执行DML标签中的selectKey标签的SQL脚本,并将结果赋值到参数对象对应的属性中
      keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
    } else {
      //执行SQL
      statement.execute(sql);
      //获取更新记录数
      rows = statement.getUpdateCount();
    }
    return rows;
  }

  /**
   * 批处理,只是获取boundSql的可执行SQL,然后添加到 {@code statment}
   * @param statement 执行 SQL 语句并返回它所生成结果的对象
   */
  @Override
  public void batch(Statement statement) throws SQLException {
    //获取可执行SQL
    String sql = boundSql.getSql();
    //添加批处理队列中
    statement.addBatch(sql);
  }

  /**
   * 用于通知Statement将[select]推送到数据库并返回对应查询结果
   * @param statement 执行 SQL 语句并返回它所生成结果的对象
   * @param resultHandler 结果处理器
   * @param  结果对象类型
   * @return
   */
  @Override
  public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
    //获取可执行SQL
    String sql = boundSql.getSql();
    //执行SQL
    statement.execute(sql);
    //处理 statement 中的所有结果集,返回结果对象集合
    return resultSetHandler.handleResultSets(statement);
  }

  /**
   * 用于通知Statement将[select]推送到数据库并返回对应游标结果
   * @param statement 执行 SQL 语句并返回它所生成结果的对象
   * @param  结果对象类型
   * @return 结果对象游标对象
   */
  @Override
  public  Cursor queryCursor(Statement statement) throws SQLException {
    //获取可执行SQL
    String sql = boundSql.getSql();
    //执行SQL
    statement.execute(sql);
    //处理statement 中的所有结果集,返回结果对象游标
    return resultSetHandler.handleCursorResultSets(statement);
  }

  /**
   * 实例化Statment对象
   * @param connection 数据库连接
   * @return 执行 SQL 语句并返回它所生成结果的对象
   */
  @Override
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    //ResultSetType.DEFAULT:表示依赖驱动进行创建Statement实例
    if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      //创建一个 Statement 对象来将 SQL 语句发送到数据库
      return connection.createStatement();
    } else {
      /**
       * ResultSetType.FORWARD_ONLY:结果集的游标只能向下滚动
       * ResultSetType.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变
       * ResultSetType.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变
       *
       * ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表。
       * ResultSet.CONCUR_UPDATABLE:能用结果集更新数据库中的表
       */
      //创建一个 Statement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

  @Override
  public void parameterize(Statement statement) {
    // N/A N/A是Not Applicable 的缩写,表示“不适用”的意思
  }

}

你可能感兴趣的:(Mybatis-StatementHandler源码解析)