Mybatis3详解(十七)——Mybatis运行原理之SqlSession的构建过程

1、SqlSession的构建过程

       在上一章,详细的介绍了SqlSessionFactory的构建过程,它是用来获取SqlSession对象的,所以本章节就主要讲述SqlSession的构建过程。

       程序代码的入口:

image

       我们知道SqlSession对象是通过SqlSessionFactory的openSession()方法获取的,所以我们先来看一下SqlSessionFactory接口中的方法:

image

       可以发现SqlSessionFactory接口提供一系列重载的openSession方法,其参数如下(这些参数的意义会在后面介绍):

  • boolean autoCommit:是否开启JDBC事务的自动提交,默认为false。
  • Connection:提供连接。
  • TransactionIsolationLevel:定义事务隔离级别。
  • ExecutorType:定义执行器类型。

       SqlSessionFactory接口的实现类为DefaultSqlSessionFactory类。所以我们去DefaultSqlSessionFactory实现类中查看重写的openSession()方法:

   //以无参的openSession()方法为例
   public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

       通过查看其它重写的方法,会发现最终都调用了openSessionFromDataSource方法,所以继续进入方法:

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
	  // 获取Configration全局配置中的environment的配置
      final Environment environment = configuration.getEnvironment();
	  // 通过environment配置构建transactionFactory对象
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
	  // 从工厂中获取一个事务实例
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
	  // 通过configuration构建Executor执行器对象
      final Executor executor = configuration.newExecutor(tx, execType);
	  // 返回SqlSession的默认实现类DefaultSqlSession
      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();
    }
  }

       上面代码中有一行是通过configuration.newExecutor(tx,execType)来构建Executor执行器对象,这一步非常重要,因为MyBatis 中所有的 Mapper 语句的执行都是通过 Executor 来执行的,它负责SQL语句的生成和查询缓存的维护 。所以我们看一下它是怎么创建的,这里调用了Configuration类中newExecutor()方法。

   // ====== Configuration 类中的方法 ======
   public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
	// 定义Executor执行器
    Executor executor;
    // 判断执行器的类型,根据传入executorType参数
    // BatchExecutor:批量执行器
    // ReuseExecutor:会执行预处理的执行器
    // SimpleExecutor:简单的执行器
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
	  // 如果没有配置,默认就为SimpleExecutor
      executor = new SimpleExecutor(this, transaction);
    }
	//如果开启了二级缓存,则使用CachingExecutor 来包装executor,
	//在查询之前都会先查询缓存中是否有对应的数据,包装的过程使用了装饰者模式
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
	// 最后使用每个拦截器重新包装executor并返回
    executor = (Executor) interceptorChain.pluginAll(executor);
	//返回创建好的Executor执行器
    return executor;
  }

       注意(这里了解就好):executor = (Executor) interceptorChain.pluginAll(executor);这个是Mybatis中的插件,它将构建一层层的代理对象,可以在执行真正的Executor的方法前,执行配置在插件中的方法对核心代码进行修改,所以不要轻易使用插件,这里用的是责任链模式。Mybatis在实例化Executor、ParameterHandler、ResultSetHandler、StatementHandler四大接口对象的时候都是调用interceptorChain.pluginAll() 方法插入进去的。其实就是循环执行拦截器链所有的拦截器的plugin() 方法。


       Executor 对象创建完之后会以参数的形式传入DefaultSqlSession的构造方法中,从而完成SqlSession对象的创建并且返回。

image

       至此SqlSession对象的创建过程也就结束了。

       SqlSession对象构建过程中的时序图:

image

2、重载的openSession方法参数介绍

       上面程序入口我们调用的是无参数的openSession()方法,那么其它重载的方法有什么用呢?这里来介绍一下有参方法中的参数含义,有四类分别为。

  • boolean autoCommit:是否开启JDBC事务的自动提交,默认为false。
  • Connection:提供连接。
  • TransactionIsolationLevel:定义事务隔离级别。
  • ExecutorType:定义执行器类型。


           ①、boolean autoCommit:是否自动提交事物,默认为false。

           如果为true就自动提交事务,后面就不要写commit()方法提交了。


           ②、TransactionIsolationLevel :事务隔离级别类,它是一个枚举类型。

    image

           可以发现默认五种隔离级别:

    1. NONE(Connection.TRANSACTION_NONE):无隔离级别
    2. READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED):读取提交内容
    3. READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED):读取未提交内容
    4. REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ):可重复读
    5. SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE):可串行化


           ③、Connection:提供连接对象。

           如果使用这种方式会优先使用这里面的数据库连接对象。如:

    image


        ④、ExecutorType :执行器类型,它是一个枚举类型。

    image

           它主要用来判断使用哪种类型的执行器Executor,因为SqlSession是真正来执行Java与数据库交互的对象,提供了查询(query)、更新(update)等方法,主要有三种类型:

    1. SIMPLE:简易执行器,如果不配置类型,就是默认执行器
    2. REUSE:能过执行重用预处理语句的执行器
    3. BATCH:执行器重用语句和批量更新,批量专用的执行

           在上面创建Executor执行器的代码中已经进行了判断。所以这里就不再多说了。

    image

           -------------------------------------------------------------------------

    image

    原文地址:https://www.cnblogs.com/tanghaorong/p/14083400.html