Mybatis源码阅读笔记四-Session的创建过程

Mybatis 3.5.5的版本
本系列的前三篇主要讲述了xml文件解析的过程和其中主要的类:

xml文件加载过程

探究SqlSource类

探究SqlNode类

在我们使用Mybatis的过程中,这只是完成了开始的准备工作,接下来就是根据需要执行我们定义的SQL。那么在这一过程中,必须要做的就是拿到SqlSession,那么我们这篇文章就来梳理SqlSession的基本情况。

一、SqlSession接口

public interface SqlSession extends Closeable {
    <T> T selectOne(String statement);
    <E> List<E> selectList(String statement);
    <K, V> Map<K, V> selectMap(String statement, String mapKey);
    <T> Cursor<T> selectCursor(String statement);
    void select(String statement, Object parameter, ResultHandler handler);
    int insert(String statement, Object parameter);
    int update(String statement, Object parameter);
    int delete(String statement, Object parameter);

    void commit(boolean force);
    void rollback(boolean force);

    List<BatchResult> flushStatements();

    void clearCache();

    <T> T getMapper(Class<T> type);

    Connection getConnection();
    Configuration getConfiguration();
}

在这里摘录的代码只是其中的一部分,在这个类中对于同一中方法定义了很多不同参数的重载方法,在这里我们只展示其中一个。我把这些方法主要分为了六类,以空行分割。第一类最多,是与我们对数据库的操作息息相关的,即select | insert | update | delete操作的方法。第二类是对数据库事务的抽象,体现出来就是commit和rollback方法。第三类是刷新批处理语句。第四类是缓存相关。第五类是与Mybatis提供的mapper代理使用方式相关的方法。最后一类是get类方法,获取某对象或属性。

上图为SqlSession接口的实现关系,我们看到有两个实现类,分别是Deafault和Manager。我们调用的openSession方法之后会返回给我们一个DefaultSqlSession的对象,下文中会详细分析。

二、openSession的具体过程

1.我们通过在SqlSessionFactory中调用openSession方法来获取一个SqlSession。我们知道SqlSessionFactory只是一个接口,那么具体我们用的是哪一个实现类呢?答案是DefaultSqlSessionFactory,我们通过这段代码可以确认:

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
      }
    }
  }
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

这段代码来自于SqlSessionFactoryBuilder类,我们可以看到,最终是创建了DefaultSqlSessionFactory并返回。

2.那么我们再看一下在DefaultSqlSessionFactory类中,openSession方法是如何运作的呢:

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

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //获取Environment对象
      final Environment environment = configuration.getEnvironment();
      //得到TransactionFactory 
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //生产一个Transaction
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //生成一个Executor
      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();
    }
  }

那么直接看到最后面返回的是一个DefaultSqlSession对象,它的构造方法需要Configuration对象(已有)、Executor对象和boolean autoCommit。默认的自动提交为false,从openSession方法中可以看出。最后剩下的就是要构建一个Excutor了,我们看一下openSessionFromDataSource的前面几句,分别是:获取Environment对象,根据Environment得到TransactionFactory,使用工厂生产一个Transaction,最后就是new一个Executor交给DefaultSqlSession的构造方法。

看这些方法名就大概知道是干什么用的了,但是具体是什么过程我们还需要从源码中阅读,接下来我们分别看一下其中用到的各个方法。

三、TransactionFactory+Transaction类

第一个获取Environment对象就不解释了,它是在xml解析过程中得到的。

首先我们会不清楚的一个地方是这个TransactionFactory+Transaction是怎么得到的,有什么属性,我们现在来看看。

首先看看TransactionFactory工厂的获得,见代码:

//DefualtSqlSessionFactory类中的方法  
  private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
      return new ManagedTransactionFactory();
    }
    return environment.getTransactionFactory();
  }

也就是说我们传递进去的Environment为空,或者其中的属性TransactionFactory为空,会创建一个ManagedTransactionFactory。如果不是这样的话,会将Environment中的TransactionFactory取出来返回,那这回是什么类型的呢,我们需要回到Environment创建的时候进行探究一下。

  //这段代码存在于XmlConfigBuilder类中
private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      if (environment == null) {
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id");
        //if语句判断的是environments标签的default属性是否与environment的id一致,一致的话才会进行解析
        if (isSpecifiedEnvironment(id)) {
          //通过这个语句我们就可以得到一个TransactionFactory,最后放到configuration中
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          DataSource dataSource = dsFactory.getDataSource();
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }

那么我们可以看到,其中决定TransactionFactory类型的就是transactionManagerElement这个方法,接着看代码:

  private TransactionFactory transactionManagerElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      Properties props = context.getChildrenAsProperties();
      TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a TransactionFactory.");
  }

我们看到其实就是根据我们配置的“transactionManager”这个标签通过反射得到TransactionFactory的,我们配置为“JDBC”(大小写无所谓)时,会生成一个叫做JdbcTransactionFactory的对象,那么它的功能就是创建JdbcTransaction对象,我们看一下它的方法:

  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }

相应的,如果我们最终获得了ManagedTransactionFactory工厂对象,那么生产出来的就是ManagedTransaction对象。

四、Executor的创建过程

  //该方法来自于Configuration类
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 {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

我们通过创建Executor的代码可以看出,创建一个什么样的Executor依据是type,那么这里面的defaultExecutorType其实也是被初始化为Simple类型的;另外一个依据就是cacheEnabled即是否使用缓存,说明了缓存与Executor息息相关。最后一句代码是在所有的拦截器中都插入Executor对象,之后我们详解Executor会进行分析。

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxzfcsu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值