• Mybatis源码解析(五):SqlSession会话的创建


    Mybatis源码系列文章

    手写源码(了解源码整体流程及重要组件)

    Mybatis源码解析(一):环境搭建

    Mybatis源码解析(二):全局配置文件的解析

    Mybatis源码解析(三):映射配置文件的解析

    Mybatis源码解析(四):sql语句及#{}、${}的解析

    Mybatis源码解析(五):SqlSession会话的创建

    Mybatis源码解析(六):缓存执行器操作流程

    Mybatis源码解析(七):查询数据库主流程

    Mybatis源码解析(八):Mapper代理原理

    Mybatis源码解析(九):插件机制

    Mybatis源码解析(十):一级缓存和二级缓存



    前言

    • 之前篇幅讲解核心配置文件和实体映射配置文件的解析,当这两者都准备就绪,则需如下第三步
    • 创建sql会话对象,为之后执行sql流程做准备
    • 本文内容也只围绕openSession方法源码来说

    在这里插入图片描述


    一、openSession()重载方法

    • 从多个重载方法可知,创建SqlSession可以指定这些单个或者多个参数
    • 如果什么都不会,会有默认值,之后源码会讲

    在这里插入图片描述

    二、执行器介绍

    • BaseExecutor基础执行器,封装了子类的公共方法,包括一级缓存、延迟加载、回滚、关闭等功能
    • SimpleExecutor简单执行器,每执行一条 sql,都会打开一个 Statement,执行完成后关闭(默认执行器)
    • ReuseExecutor重用执行器,相较于 SimpleExecutor 多了 Statement 的缓存功能,其内部维护一个 Map ,每次编译完成的 Statement 都会进行缓存,不会关闭(如:相同请求jdbc底层操作PreparedStatement不用每次创建)
    • BatchExecutor批量执行器,基于 JDBC 的 addBatch、executeBatch 功能,并且在当前 sql 和上一条 sql 完全一样的时候,重用 Statement,在调用doFlushStatements 的时候,将数据刷新到数据库
    • CachingExecutor缓存执行器,装饰器模式,在开启缓存的时候。会在上面三种执行器的外面包上 CachingExecutor(具体执行操作还是上面的执行器)

    在这里插入图片描述

    三、openSession()方法解析入口

    • 我们调用的无参方法,则看第一个,其他的则是有参的入口
    • 参数1:执行器类型,在核心配置文件中初始化中有,这里只是给了一个简单类型的枚举类型
      在这里插入图片描述
    • 参数2:事务隔离级为空
    • 参数3:事务默认非自动提交,那么做增删改,则需要手动commit
    @Override
    public SqlSession openSession() {
      // 调用openSessionFromDataSource 参数1:执行器类型  参数2:事务隔离级别  参数三:指定事务是否自动提交
      return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
    }
    
    @Override
    public SqlSession openSession(boolean autoCommit) {
      return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
    }
    
    @Override
    public SqlSession openSession(ExecutorType execType) {
      return openSessionFromDataSource(execType, null, false);
    }
    
    @Override
    public SqlSession openSession(TransactionIsolationLevel level) {
      return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    四、通过数据源创建会话对象

    • 通过环境对象创建事务对象
    • 创建执行器对象
    • 由执行器及其他参数构建DefaultSqlSession会话对象
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
      Transaction tx = null;
      try {
        // 从configuration对象中获取environment对象
        final Environment environment = configuration.getEnvironment();
        // 获得事务工厂对象
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        // 构建事务对象
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 创建执行器对象
        final Executor executor = configuration.newExecutor(tx, execType);
        // 创建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();
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1、Environment环境对象

    • 从如下配置文件解析成Environment对象,这些源码在Mybatis源码解析(二):全局配置文件的解析有讲
      • id:环境id,可以配置多个环境,如这里的id=development
      • transactionFactory:事务工厂对象,如这里的JDBC,这是注册的别名,实际是JdbcTransactionFactory事务工厂类
      • dataSource:数据源对象,如这里的POOLED,这是注册的别名,实际是PooledDataSourceFactory数据源工厂类
    • 通过type获取Class对象,然后反射创建对象,注入xml中的属性值,填充对象,创建工厂对象完成
    public final class Environment {
      private final String id;
      private final TransactionFactory transactionFactory;
      private final DataSource dataSource;
      ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    2、构建事务对象

    • 进入事务工厂类的newTransaction方法
    • 创建JdbcTransaction事务对象,数据源、事务隔离级别、是否自动提交构造赋值
    public class JdbcTransactionFactory implements TransactionFactory {
    
      @Override
      public Transaction newTransaction(Connection conn) {
        return new JdbcTransaction(conn);
      }
    
      @Override
      public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
        return new JdbcTransaction(ds, level, autoCommit);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3、构建执行器

    • 通过枚举类型判断创建批量执行器或者重用执行器还是默认简单执行器
    • cacheEnabled:全局配置文件的属性,是否开启一级缓存,默认开启
    • 开启缓存,则会创建CachingExecutor缓存执行器,将真正操作数据的执行器传入
    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);
      }
      // 如果允许缓存,会通过CachingExecutor 去代理一层
      if (cacheEnabled) {
        executor = new CachingExecutor(executor);
      }
      // 拦截器插件
      executor = (Executor) interceptorChain.pluginAll(executor);
      return executor;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    进入CachingExecutor构造方法

    • CachingExecutor只是做数据缓存的操作,而真正的数据处理还是要交给delegate,也就是批量执行器、重用执行器或者简单执行器
    • 默认不关闭缓存的情况下:不论一级缓存还是二级缓存,都是通过外面包一层缓存执行器来实现
    public class CachingExecutor implements Executor {
    
      private final Executor delegate;
      private final TransactionalCacheManager tcm = new TransactionalCacheManager();
    
      public CachingExecutor(Executor delegate) {
        this.delegate = delegate;
        delegate.setExecutorWrapper(this);
      }
    
      ...
      
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    总结

    • 创建SqlSession会话对象这一步是一个承上启下的作用,利用上几步解析xml的对象构建以后执行sql的执行器
    • sql的执行及会话的关闭等核心代码都在执行器中,具体内容后面篇幅再讲
  • 相关阅读:
    12 个适合做外包项目的开源后台管理系统
    SENET和GateNet(推荐系统(embedding))
    arcgis插件 批量出图 按地块批量出图工具
    LeetCode【279】完全平方数
    C++中的通俗理解左值,右值,左值引用,右值引用
    江苏建筑模板厂家-建筑模板批发供应商
    RDMA 优势
    OPCHDA接口
    通俗介绍人工智能是什么
    java-python-net-php-基于SSM的汽车保险销售信息管理系统计算机毕业设计程序
  • 原文地址:https://blog.csdn.net/qq_35512802/article/details/127836774