Hey, Nice to meet You. 

人之节.人情有所不能忍者,匹夫见辱,拔剑而起,挺身而斗,此不足为勇也,天下有大勇者,猝然临之而不惊,无故加之而不怒.此其所挟持者甚大,而其志甚远也.          ☆☆☆所谓豪杰之士,必有过

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()方法:

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
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()方法。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ====== 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

posted @   唐浩荣  阅读(641)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!
点击右上角即可分享
微信分享提示

目录导航