User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   SQL   ›   MyBatis   ›   正文
MyBatis

Mybatis原理—SqlSession的构建过程

2022-03-04 18:32:49
522  0 1
参考目录 隐藏
1) SqlSession的构建过程
2) 重载的openSession方法参数介绍

阅读完需:约 7 分钟

SqlSession的构建过程

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

Mybatis原理—SqlSessionFactory的构建过程

程序代码的入口:

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

public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);

  SqlSession openSession(Connection connection);

  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);

  SqlSession openSession(ExecutorType execType, boolean autoCommit);

  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

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

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

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

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

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

  /**
   * 方法实现说明:从session中开启一个数据源
   * @author:xsls
   * @param execType:执行器类型
   * @param level:隔离级别
   * @return:SqlSession
   * @exception:
   * @date:2019/9/9 13:38
   */
  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);
      /**
       * 创建一个sql执行器对象
       * 一般情况下 若我们的mybaits的全局配置文件的cacheEnabled默认为ture就返回
       * 一个cacheExecutor,若关闭的话返回的就是一个SimpleExecutor
       */
      final Executor executor = configuration.newExecutor(tx, execType);
      /**
       * 创建返回一个DeaultSqlSessoin对象返回
       */
      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()方法。

  /**
   * 方法实现说明:创建一个sql语句执行器对象
   * @author:xsls
   * @param transaction:事务
   * @param executorType:执行器类型
   * @return:Executor执行器对象
   * @exception:
   * @date:2019/9/9 13:59
   */
  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 {
      //简单的sql执行器对象
      executor = new SimpleExecutor(this, transaction);
    }
    //判断mybatis的全局配置文件是否开启缓存
    if (cacheEnabled) {
      //把当前的简单的执行器包装成一个CachingExecutor
      executor = new CachingExecutor(executor);
    }
    /**
     * TODO:调用所有的拦截器对象plugin方法
     */
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

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


Executor分成两大类,一类是CacheExecutor,另一类是普通Executor。普通Executor又分为三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。

  • SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
  • ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
  • BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。CacheExecutor其实是封装了普通的Executor,和普通的区别是在查询前先会查询缓存中是否存在结果,如果存在就使用缓存中的结果,如果不存在还是使用普通的Executor进行查询,再将查询出来的结果存入缓存。


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

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

拿到SqlSession就可以执行各种CRUD方法了

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


重载的openSession方法参数介绍

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

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

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

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

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

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

  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:提供连接对象。

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

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

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

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

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


如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

1 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 594012浏览

随机文章
Axios的简单使用
5年前
JAVA对json操作—Jackson,Gson,fastjson
5年前
Java—并发编程(八)线程池– (5) 线程池的原理
3年前
Spring—DelegatingFilterProxy的作用与用法 (过滤器授权代理)
5年前
Java—并发编程(六)JUC锁 – (1)总览
4年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 594012 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付