Mybatis执行sql过程源码解读

Mybatis解析xml文件

前面已经大概了解了Mybatis是怎样解析xml文件,这篇文章就来了解一下Mybatis执行sql整体过程。

SqlSession

SqlSession根据StatementId执行查询

String resource = "mybatis-config.xml";
        Reader reader;
        try {
            //将XML配置文件构建为Configuration配置类
            reader = Resources.getResourceAsReader(resource);
            // 通过加载配置文件流构建一个SqlSessionFactory  DefaultSqlSessionFactory
            SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
            // 数据源 执行器  DefaultSqlSession
            SqlSession session = sqlMapper.openSession();
            try {
                // SqlSession执行查询
                User user = (User) session.selectOne("com.tuling.mapper.UserMapper.selectById", 1);

SqlSession只是一个门面模式,真正执行sql的是Executor

Executor有5种

  • SimpleExecutor:遇到insrt|update语句后,创建Statement对象,执行完毕后立即关闭Statement对象,只使用一次

  • BatchExecutor:遇到update语句后(JDBC只支持update批量操作),将所有的update语句添加到批处理中(addBatch()),多个Statement对象在addBatch()完后,等待执行executeBatch(),逐一执行

  • ReuseExecutor:遇到insrt|update语句后,根据SQL Id找Statement对象,如果有直接拿来用,如果没有就创建,然后放入Map<String,<Statement>>中,重复使用Statement对象

  • CachingExecutor(实现了二级缓存)

  • BaseExecutor(实现了一级缓存)

1.SqlSession对象在调用openSession()过程中创建Executor对象

/**
   * 方法实现说明:从session中开启一个数据源
   * @author:sxl
   * @param execType:执行器类型
   * @param level:隔离级别
   * @return:SqlSession
   * @exception:
   * @date:2019/9/9 13:38
   */
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      /**
       * 获取环境变量
       */
      final Environment environment = configuration.getEnvironment();
      /**
       * 获取事务工厂
       */
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      /**
       * 创建一个sql执行器对象
       * 一般情况下 若我们的mybaits的全局配置文件的cacheEnabled默认为ture就返回
       * 一个cacheExecutor,若关闭的话返回的就是一个SimpleExecutor
       */
      final Executor executor = configuration.newExecutor(tx, execType);
      /**
       * 创建返回一个DeaultSqlSessoin对象返回
       */
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

2.plugin 使用责任链( interceptorChai)+代理模式用于增强4大核心对象,

Executor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)

ParameterHandler(getParameterObject,setParameter)

ResultSetHandler(handleResultSets,handleOutputParameters)

StatementHandler(prepare,parameterize,batch,update,query)

/**
   * 方法实现说明:创建一个sql语句执行器对象
   * @author:xsls
   * @param transaction:事务
   * @param executorType:执行器类型
   * @return:Executor执行器对象
   * @exception:
   * @date:2019/9/9 13:59
   */
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    /**
     * 判断执行器的类型
     * 批量的执行器
     */
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      //可重复使用的执行器
      executor = new ReuseExecutor(this, transaction);
    } else {
      //简单的sql执行器对象
      executor = new SimpleExecutor(this, transaction);
    }
    //判断mybatis的全局配置文件是否开启缓存
    if (cacheEnabled) {
      //把当前的简单的执行器包装成一个CachingExecutor
      executor = new CachingExecutor(executor);
    }
    /**
     * TODO:调用所有的拦截器对象plugin方法
     */
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

3.SqlSession.selectOne()调用selectList()

 /**
   * 方法实现说明
   * @author:sxl
   * @param statement: statementId
   * @param parameter:参数对象
   * @param rowBounds :mybiats的逻辑分页对象
   * @return:
   * @exception:
   * @date:2019/9/9 20:33
   */
  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      /**
       * 第一步:通过我们的statement去我们的全局配置类中获取MappedStatement
       */
      MappedStatement ms = configuration.getMappedStatement(statement);
      /**
       * 通过执行器去执行我们的sql对象
       * 第一步:包装我们的集合类参数
       * 第二步:一般情况下是executor为cacheExetory对象
       */
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

4.Executor执行sql过程

 // 如果开启了二级缓存会CacheExecutor执行query方法
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    /**
     * 判断我们我们的mapper中是否开启了二级缓存<cache></cache>
     */
    Cache cache = ms.getCache();
    /**
     * 判断是否配置了cache
     */
    if (cache != null) {
      //判断是否需要刷新缓存
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        /**
         * 先去二级缓存中获取
         */
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        /**
         * 二级缓存中没有获取到
         */
        if (list == null) {
          //通过查询数据库去查询
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          //加入到二级缓存中
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //没有整合二级缓存,直接去查询
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

5.SimpleExecutor执行doQuery(),这个过程中会创建PerpareStatementHandler对象

  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

6.PerpareStatement执行sql

 @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    return resultSetHandler.handleResultSets(ps);
  }

7.ResultSetHandler处理返回值,返回数据

 @Override
  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;
    ResultSetWrapper rsw = getFirstResultSet(stmt);

    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    int resultMapCount = resultMaps.size();
    validateResultMapsCount(rsw, resultMapCount);
    while (rsw != null && resultMapCount > resultSetCount) {
      ResultMap resultMap = resultMaps.get(resultSetCount);
      handleResultSet(rsw, resultMap, multipleResults, null);
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }

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

总结

1.SqlSession.openSession()创建了Executor对象(真正的sql执行者),这个对象有两大类普通Executor和CacheExecutor(实现二级缓存),BaseExecutor实现一级缓存。如果配置了插件,在创建Executor的过程中会创建Executor的代理。

2.Executor执行查询sql,从Cofiguration对象中获取MappedStatement(里面封装了sql信息),Executor由于是代理类,执行Plugin的invoke方法,做完中间处理之后,CacheExecutor先去二级缓存中找,如果找不到再调用BaseExecutor到一级缓存中找,还找不到就访问数据库,然后把数据放入一二级缓存,最终将数据返回。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值