[Mybatis] Mybatis运作流程分析

因为机缘关注起来Mybatis,本文将探索Mybatis的整体执行流程,了解其大概是如何运作的。

Mybatis示例

    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(inputStream);

    SqlSession sqlSession = factory.openSession();
    sqlSession.selectList("selectAllUser");

    sqlSession.close();

一次Mybatis执行如上,前面三行代码应该就是扫描xml信息注册起来为后面提供使用,我们重点关注的是中间的那两行,它们是如何实现一次完整的查询的,上面的factory默认实现类为DefaultSqlSessionFactory。用此类来创建一个SqlSession,有关的SQL操作就是在SqlSession中执行的。

SqlSessionFactory

该接口的默认实现类是DefaultSqlSessionFactory

public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;//配置信息

  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

  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);
      //实例化一个Executor,默认为SimpleExecutor,SqlSession就是使用Executor来执行SQL的。
      final Executor executor = configuration.newExecutor(tx, execType);
      //根据Executor生成一个SqlSession。
      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();
    }
  }

}

SqlSession

该接口的默认实现类是DefaultSqlSession,上面生成的SqlSession就是该类的对象

public class DefaultSqlSession implements SqlSession {

  private Configuration configuration;
  //该executor为CachingExecutor,前文我们说了executor是用于执行SQL的,但是此处的executor并不是真正的执行器,只是一个静态代理执行器,mybatis的二级缓存就是在此实现的
  private Executor executor;

  private boolean autoCommit;//是否自动提交
  private boolean dirty;

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      //从配置中获取到MappedStatement信息,MappedStatement封装了一条SQL相应的信息,
      MappedStatement ms = configuration.getMappedStatement(statement);
      //将MappedStatement交给代理执行器CachingExecutor执行
      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();
    }
  }

}

Executor

Mybatis的执行核心在Executor,它有好多个实现类,批量执行等就是在该接口中实现的,本文只关注SimpleExecutor整个实现类,也就是简单查询。

在调用真正的SimpleExecutor之前,Mybatis还调用了一个CachingExecutor。代码如下

public class CachingExecutor implements Executor {//缓存执行器,是一个代理的执行器。
  //它的实例对象为SimpleExecutor,是真正执行器的实现类
  private Executor delegate;
  private TransactionalCacheManager tcm = new TransactionalCacheManager();

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    //这就是CachingExecutor进一步要做的事,判断是否存在缓存,是则从缓存中获取,这是二级缓存。后文还有个个二级缓存
    Cache cache = ms.getCache();//从ms获取缓存
    if (cache != null) {//缓存不为空直接从缓存中返回
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //无缓存数据从数据库中查询返回
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

}

上面的分析中我们知道SQL的执行最终是由SimpleExecutor去执行的。来看下SimpleExecutor的结构

org.apache.ibatis.executor.Executor
    org.apache.ibatis.executor.BaseExecutor
        org.apache.ibatis.executor.SimpleExecutor

BaseExecutor是一个抽象类,实现了Executor接口

public abstract class BaseExecutor implements Executor {

  @SuppressWarnings("unchecked")
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      //是否存在缓存,注意此处的缓存不等于CacheExecutor的缓存,这个是一级缓存。
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {//不存在缓存则从数据库中查询
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

 //从数据库中查询
  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      //注意此处,doQuery()方法是一个抽象方法,由子类去实现。
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

  //抽象方法,也就是说具体的查询由子类去实现
  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;  

}

再看子类SimpleExecutor,这个才是查询的真正实现类

public class SimpleExecutor extends BaseExecutor {

  @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);
      //从配置文件中获取一个Statement
      stmt = prepareStatement(handler, ms.getStatementLog());
      //注意参数stmt,将这个Statement传入到query()方法中。
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }


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

}

最后看SimpleStatementHandler是如何实现查询的。

public class SimpleStatementHandler extends BaseStatementHandler {

  @Override
  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    String sql = boundSql.getSql();//生成要执行的SQL
    statement.execute(sql);//这个就是真正实现查询的语句了,很熟悉吧,其实就是jdbc的内容了。
    return resultSetHandler.<E>handleResultSets(statement);
  }

}

本文为了快速了解整个Mybatis的运作流程,省略很多内容,如executor接口有很多的实现类,在此文中只给了一个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值