Mybatis源码阅读2 --- 流程概要分析

这一篇简单查看下mybatis的执行流程及核心的类。


上文中查询的代码:

InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
City city = sqlSession.selectOne("com.hhg.jerry.dao.CityDao.getById",1L);

对框架使用者而言:

1、指定配置文件生成InputStream

2、根据InputStream构建SqlSessionFactory

3、SqlSessionFactory打开SqlSession

4、SqlSession执行crud(create、retrive、upate、delete)

下面根据mybatis源码说明下步骤 2、3、4

step2:InputStream经过XMLConfigBuilder解析为Configuration对象,通过configuration构造出DefaultSqlSessionFactory。构建configuration时解析的xml元素如下:

 
 
 private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

注意到我们现在仅仅配置了environmentsmappers,Mybaits就能够运行的。如何解析每个element建议先别看,因为我们要了解的是主流程,而不是细节。

step3:SqlSessionFactory创建SqlSession,重载了几个方法,但最终调用的是一个方法:

    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);
            final Executor executor = configuration.newExecutor(tx, execType);
            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();
        }
    }

参数: ExecutorType->枚举类(具体不清楚) TransactionIsolationLevel->枚举类 隔离级别 autoCommit->自动提交

函数体:先构建一个Transaction,通过transaction构建Executor,executor又构建了DefaultSqlSession

到此只看到了一些外表,先不看细节,继续往下看。

step4: SqlSession的查询,sqlSession.selectOne("com.hhg.jerry.dao.CityDao.getById",1L);简单跟进去后就到这里了:

    @Override
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
            MappedStatement ms = configuration.getMappedStatement(statement);
            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();
        }
    }

根据statement("com.hhg.jerry.dao.CityDao.getById")拿到MappedStatement对象,SqlSession的executor去继续query,此executor是CachedExecutor,但我们并没有配置缓存啊,先继续debug就到了BaseExecutor的query方法中:

list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
    handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
    list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

localCache.get,还是从缓存中取,取不到就queryFromDatabase,我们再debug方法queryFromDatabase,最终到了SimpleExecutor类中(CacheExcutor的delegate就是SimpleExecutor)的doquery方法:

    @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.<E>query(stmt, resultHandler);
        } finally {
            closeStatement(stmt);
        }
    }

StatementHandler是什么?一会再看他,prepareStatement方法返回了Statement(JDBC的接口):

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

咦,这不是JDBC的东西了吗?终于找到你大笑,回到SimpleExecutor的doquery方法,最后return了handler.query,来看下这个方法,在PrepareStatementHandler类中:

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

还是JDBC的那一套,只不过用resultHandler处理了查询结果,后续就是一层层的返回这个结果了

到这里mybaits的执行流程就被我们走马观花的看了一遍,总结一下:Session -> Executor -> JDBC -> ResultHandler -> 结果 ,细节暂时都不清楚。配置文件也没配全,也不清楚。下一步就是单独的功能点分析,会深入这些细节,同时配置也会全起来


还记得流程中有个CacheExecutor和localCache.get吗? 他们干吗用的? 且看下回分解,mybaits缓存

猜你喜欢

转载自blog.csdn.net/lnlllnn/article/details/80703043