Mybatis源码学习-核心流程-数据访问阶段


所用到的设计模式:
模板模式、装饰器模式
模板模式:定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。(定义好方法的执行步骤,但是方法的具体内容由子类去实现)
例如:
mybatis中的query方法
AbstractQueuedSynchronizer 中的 acquire等一系列方法

装饰器模式:对某些类进行装饰,用来扩展功能的设计模式。

Executor – 对数据库访问

由绑定阶段可得知,接口调用的方法,全部转发给了SqlSession,而SqlSession将所有的实现都转给的Executor。
它是MyBatis核心接口之一,定义了数据库操作的最基本的方法,其内部遵循JDBC规范完成对数据库的访问。

Executor类继承图
在这里插入图片描述
Executor:MyBatis核心接口之一,定义了数据库操作的最基本的方法。

BaseExecutor:实现了接口的大部分方法,主要提供了缓存管理(一级)和事务管理的能力,其他子类需要实现抽象方法doUpdate,doQuery等

CachingExecutor:对Executor增强了二级缓存的能力,如果二级缓存没有,在去执行BaseExecutor中的query方法
SimpleExecutor: 默认执行器,每次都会创建一个statement,用完后关闭(使用的是PrepareStatemnet对象)
ReuseExecutor: 可重用执行器,将statement存入map中,操作map中的statement,不会去重复创建(使用的是PrepareStatemnet对象)
BatchExecutor: 批量执行所有的更新语句,基于jdbc的batch操作实现批处理
ClosedExecutor: 内部类,外部没法使用,可以不用了解

Created with Raphaël 2.2.0 SqlSession执行SQL Executor.query 获取sql信息(BoundSql) 拼装CacheKey 判断是否需要清空一级缓存 根据CacheKey查找一级缓存 是否命中一级缓存? 返回结果 查询数据库 将结果保存到一级缓存中 缓存延迟加载处理 yes no

在执行query方法中,有3个重要的类要知道

StatementHandler – 定义了操作数据库的基本方法

定义了操作数据库的基本方法,是完成MyBatis最核心的工作,也是Executor实现的基础

/**
 * Executor实现的基础;功能包括:创建statement对象,为sql语句绑定参数,执行增删改查等SQL语句、将结果映射集进行转化
 * @author Clinton Begin
 * 
 */
public interface StatementHandler {

 //从连接中获取一个Statement
  Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;

  //占位符处理,绑定statement执行时需要的实参
  void parameterize(Statement statement)
      throws SQLException;
 //批量执行sql语句
  void batch(Statement statement)
      throws SQLException;
//执行update/insert/delete语句
  int update(Statement statement)
      throws SQLException;

//执行select语句
  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;

  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;

  //获取sql语句
  BoundSql getBoundSql();

  //获取封装的参数处理器
  ParameterHandler getParameterHandler();

}

其继承关系如下图
在这里插入图片描述

RoutingStatementHandler

Excutor组件真正实例化的子类,使用静态代理模式,根据上下文决定创建哪个具体实体类;

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //RoutingStatementHandler最主要的功能就是根据mappedStatment的配置,生成一个对应的StatementHandler对象并赋值给delegate
    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());
    }

  }

BaseStatementHandler

所有子类的抽象父类,定义了初始化 statement 的操作顺序,由子类实现具体的实例化不同的 statement

//使用模板模式,定义了获取Statement的步骤,其子类实现实例化Statement的具体的方式;
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      //通过不同的子类实例化不同的Statement,分为三类:simple(statment)、prepare(prepareStatement)、callable(CallableStatementHandler)
      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);
    }
  }

PreparedStatementHandler

使用prepareStatement对象来完成对数据库的操作

//使用底层的prepareStatement对象来完成对数据库的操作
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    //根据mappedStatement.getKeyGenerator字段,创建prepareStatement
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {//对于insert语句
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
    	//返回数据库生成的主键
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
    	//返回数据库生成的主键填充至keyColumnNames中指定的列
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() != null) {
     //设置结果集是否可以滚动以及其游标是否可以上下移动,设置结果集是否可更新
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      //创建普通的prepareStatement对象
      return connection.prepareStatement(sql);
    }
  }

SimpleStatementHandler – 直接使用Statement对象

使用statment对象来完成对数据库的操作

//使用底层的statment对象来完成对数据库的操作
  protected Statement instantiateStatement(Connection connection) throws SQLException {
    if (mappedStatement.getResultSetType() != null) {
    	//设置结果集是否可以滚动以及其游标是否可以上下移动,设置结果集是否可更新
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.createStatement();
    }
  }

CallableStatementHandler – 调用存储过程

调用存储过程

protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getResultSetType() != null) {
      return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.prepareCall(sql);
    }
  }

ParameterHandler

对预编译的SQL语句进行参数设置,其实现类是 DefaultParameterHandler
主要方法是setParameters()

@Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    //从boundSql中获取sql语句的占位符对应的参数信息
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    //遍历这个参数列表,把参数设置到PreparedStatement中
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);//获得入参的形参名字,javatype,jdbctype等信息
        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();//从parameterMapping中获取typeHandler对象
          JdbcType jdbcType = parameterMapping.getJdbcType();//获取参数对应的jdbcType
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
        	 //为statment中的占位符绑定参数
            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);
          }
        }
      }
    }
  }

ResultSetHandler – 封装结果集

对数据库返回的结果集进行封装,返回用户指定的类型 ,其实现类是DefaultResultSetHandler
主要方法是handleResultSets() 跟handleResultSet()
实际上是三个步骤:
1.找到映射匹配规则
2.反射实例化目标对象
3.根据规则填充属性值
在这里插入图片描述

public List<Object> handleResultSets(Statement stmt) throws SQLException {
    ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    //用于保存结果集对象
    final List<Object> multipleResults = new ArrayList<>();

    int resultSetCount = 0;
    //statment可能返回多个结果集对象,这里先取出第一个结果集
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    //获取结果集对应resultMap,本质就是获取字段与java属性的映射规则
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);//结果集和resultMap不能为空,为空抛出异常
    while (rsw != null && resultMapCount > resultSetCount) {
     //获取当前结果集对应的resultMap
      ResultMap resultMap = resultMaps.get(resultSetCount);
      //根据映射规则(resultMap)对结果集进行转化,转换成目标对象以后放入multipleResults中
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);//获取下一个结果集
      cleanUpAfterHandlingResultSet();//清空nestedResultObjects对象
      resultSetCount++;
    }
    //获取多结果集。多结果集一般出现在存储过程的执行,存储过程返回多个resultset,
    //mappedStatement.resultSets属性列出多个结果集的名称,用逗号分割;
    //多结果集的处理不是重点,暂时不分析
    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
      while (rsw != null && resultSetCount < resultSets.length) {
        ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
        if (parentMapping != null) {
          String nestedResultMapId = parentMapping.getNestedResultMapId();
          ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
          handleResultSet(rsw, resultMap, null, parentMapping);
        }
        rsw = getNextResultSet(stmt);
        cleanUpAfterHandlingResultSet();
        resultSetCount++;
      }
    }

    return collapseSingleResultList(multipleResults);
  }

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
      if (parentMapping != null) {//处理多结果集的嵌套映射
        handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
      } else {
        if (resultHandler == null) {//如果resultHandler为空,实例化一个人默认的resultHandler
          DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
          //对ResultSet进行映射,映射结果暂存在resultHandler中
          handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
          //将暂存在resultHandler中的映射结果,填充到multipleResults
          multipleResults.add(defaultResultHandler.getResultList());
        } else {
          //使用指定的rusultHandler进行转换
          handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
        }
      }
    } finally {
      // issue #228 (close resultsets)
      //调用resultset.close()关闭结果集
      closeResultSet(rsw.getResultSet());
    }
  }

Executor的运行流程如下图:
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值