首页 > 数据库 >Mybatis 源码(五):SqlSession对象构建

Mybatis 源码(五):SqlSession对象构建

时间:2023-03-20 18:24:07浏览次数:53  
标签:执行器 缓存 对象 创建 executor SqlSession 源码 Executor Mybatis

  SqlSession对象创建核心在SQL执行器Executor对象的创建,sqlSession持有Executor对象。

1、SqlSession对象的创建

应用程序每次操作数据库,都需要创建一个sqlSession对象,通过sqlSession完成SQL语句的执行。下面来看看sqlSession的创建过程。

// 获取sqlSession 
SqlSession sqlSession = sqlSessionFactory.openSession();

1.1、SqlSessionFactory默认实现子类

  SqlSesiionFactory的类图如下:

   0

  SqlSessionFactory有两个子类DefaultSqlSessionFactory、SqlSessionManager,Mybatis默认使用DefaultSqlSessionFactory的openSession()方法创建sqlSession对象。

1.2、openSession()

  创建数据库连接会话对象,DefaultSqlSessionFactory#openSession() 核心代码

1 // 获取数据库的会话,创建出数据库连接的会话对象SqlSession
2 public SqlSession openSession() {
3     // 从数据源中获取sqlSession
4     return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
5 }

1.3、openSessionFromDataSource()

  从数据源中获取sqlSession,DefaultSqlSessionFactory#openSessionFromDataSource() 核心代码:

 1 // 从数据源中获取会话对象 -> sqlSession
 2 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
 3   Transaction tx = null;
 4   try {
 5     // 获取mybatis-config.xml配置文件中配置的Environment对象,
 6     final Environment environment = configuration.getEnvironment();
 7     // 获取TransactionFactory对象
 8     final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
 9     // 创建Transaction对象
10     tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
11     // 根据配置创建Executor对象
12     final Executor executor = configuration.newExecutor(tx, execType);
13     //然后产生一个DefaultSqlSession
14     return new DefaultSqlSession(configuration, executor, autoCommit);
15   } catch (Exception e) {
16     //如果打开事务出错,则关闭它
17     closeTransaction(tx); // may have fetched a connection so lets call close()
18     throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
19   } finally {
20     //最后清空错误上下文
21     ErrorContext.instance().reset();
22   }
23 }

1、获取事务对象transaction

1.1、获取事务工厂对象transactionFactory

  获取配置类configuration中的environment环境属性,有关environment的配置解析,详见Mybatis 源码(三):Mybatis配置解析

  environment环境中持有事务工厂TransactionFactory、数据源DataSource。解析environmet配置时的核心代码段如下:

  根据全局配置,从环境配置中获取事务工厂JdbcTransactionFactory,DefaultSqlSessionFactory#getTransactionFactoryFromEnvironment() 核心代码:

1 // 从环境配置中获取事务工厂
2 private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
3   //如果没有配置事务工厂,则返回托管事务工厂
4   if (environment == null || environment.getTransactionFactory() == null) {
5     return new ManagedTransactionFactory();
6   }
7   // 返回配置的事务工厂
8   return environment.getTransactionFactory();
9 }

1.2、创建事务对象transaction

  根据事务工厂创建事务对象transaction,根据全局配置创建的是JdbcTransaction,JdbcTransactionFactory#newTransaction() 核心代码

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

2、创建执行器Executor对象

  创建执行器对象Executor, Configuration#newExecutor(Transaction transaction, ExecutorType executorType) 核心代码:

 1 // 创建执行器
 2 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
 3   executorType = executorType == null ? defaultExecutorType : executorType;
 4   executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
 5   Executor executor;
 6   // 根据参数,选择合适的Executor实现
 7   if (ExecutorType.BATCH == executorType) {
 8     executor = new BatchExecutor(this, transaction);
 9   } else if (ExecutorType.REUSE == executorType) {
10     executor = new ReuseExecutor(this, transaction);
11   } else {
12     executor = new SimpleExecutor(this, transaction);
13   }
14   // 根据配置决定是否开启二级缓存的功能
15   if (cacheEnabled) {
16     executor = new CachingExecutor(executor);
17   }
18   // 此处调用插件,通过插件可以改变Executor行为
19   executor = (Executor) interceptorChain.pluginAll(executor);
20   return executor;
21 }

1、newExecutor方法参数

  newExecutor方法有两个参数,Transaction参数通过configuration中的environment属性持有的事务工厂创建的JdbcTransaction。

  ExecutorType参数是Mybtais中默认的执行器类型,通过DefaultSqlSessionFactory#openSession()方法进行传递。

1 public SqlSession openSession() {
2   // 从数据源中获取会话对象
3   return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
4 }

  Mybatis中默认执行器类型ExecutorType.SIMPLE,配置类中configuration的defaultExecutorType属性:

// 默认简单执行器
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

  执行器ExecutorType枚举,最常用的执行器类型是Simple。

1 /**
2  * SIMPLE 为每个语句的执行创建一个新的预处理语句。
3  * REUSE  复用预处理语句
4  * BATCH  批量执行所有更新语句
5  */
6 public enum ExecutorType {
7   SIMPLE, REUSE, BATCH
8 }

2、根据执行器类型,创建不同的SQL执行器

  根据不同的执行器类型,创建不同Executor执行器,Executor执行器中持有Configuration配置对象、Transaction事务对象。

  执行器Executor接口类图如下:

  

  执行器类型ExecutorType枚举中,分别对应SimpleExecutor、BatchExecutor、ReuseExecutor,都继承自Executor接口,Executor接口详情:

 1 // 执行器
 2 public interface Executor {
 3 
 4   // 不需要ResultHandler
 5   ResultHandler NO_RESULT_HANDLER = null;
 6 
 7   // 执行insert、delete、update三种类型的SQL语句
 8   int update(MappedStatement ms, Object parameter) throws SQLException;
 9 
10   // 执行select类型的SQL语句,返回值分为结果对象列表或游标对象
11   <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
12 
13   // 查询,带分页
14   <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
15 
16   <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
17 
18   // 批量执行SQL语句
19   List<BatchResult> flushStatements() throws SQLException;
20 
21   // 提交事务
22   void commit(boolean required) throws SQLException;
23 
24   // 回滚事务
25   void rollback(boolean required) throws SQLException;
26 
27   // 创建缓存中用到的CacheKey对象
28   CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
29 
30   // 根据CacheKey对象查找缓存
31   boolean isCached(MappedStatement ms, CacheKey key);
32 
33   // 清空一级缓存
34   void clearLocalCache();
35 
36   // 延迟加载一级缓存中的数据
37   void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
38 
39   // 获取事务对象
40   Transaction getTransaction();
41 
42   // 关闭Executor对象
43   void close(boolean forceRollback);
44 
45   // 检测Executor是否已关闭
46   boolean isClosed();
47 
48   void setExecutorWrapper(Executor executor);
49 }

  Executor执行器主要完成SQL的执行操作,也包含对事务、缓存的处理。

3、缓存的处理

  从configuration配置类是否开启缓存配置,默认开启。可在标签中设置缓存是否开启。

// 开启缓存标识
protected boolean cacheEnabled = true;

  若缓存开启,创建缓存执行器CachingExecutor, 持有SimpleExecutor等执行器,事务缓存管理器TransactionalCacheManager对象。

 1 public class CachingExecutor implements Executor {
 2 
 3   private final Executor delegate;
 4   private final TransactionalCacheManager tcm = new TransactionalCacheManager();
 5 
 6   public CachingExecutor(Executor delegate) {
 7     this.delegate = delegate;
 8     delegate.setExecutorWrapper(this);
 9   }
10   // ...
11 }

  CachingExecutor详情如下:

  

3、创建SqlSession

  DefaultSqLSession构造函数:

 1 // configuration配置对象
 2 private final Configuration configuration;
 3 // 底层依赖的Executor对象
 4 private final Executor executor;
 5 // 是否自动提交
 6 private final boolean autoCommit;
 7 // 当前缓存中是否有脏数据
 8 private boolean dirty;
 9 
10 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
11   this.configuration = configuration;
12   this.executor = executor;
13   this.dirty = false;
14   this.autoCommit = autoCommit;
15 }

2、核心流程图

   创建sqlSession对象核心流程如下:

 

  

 

3、总结

  sqlSession对象的创建过程中,最重要的是创建了SQL执行器Executor对象,主要步骤:

  创建Executor需要事务对象,通过configuration中environment属性获取事务工厂创建事务对象。

2、创建Executor对象 - 根据执行器类型、是否开启缓存创建不同的Executor

  2.1、根据不同的执行器类型创建不同的Executor对象(simple/reuse/batch);

  2.2、判断是否开启缓存,若开启缓存,创建缓存执行器CachingExecutor封装SimpleExecutor/ReuseExecutor/BatchExecutor对象。

3、创建SqlSession对象

  创建sqlSession对象,持有Executor对象。

 

标签:执行器,缓存,对象,创建,executor,SqlSession,源码,Executor,Mybatis
From: https://www.cnblogs.com/RunningSnails/p/17237255.html

相关文章

  • Mybatis 源码(四):Mapper的解析工作
    1、Mapper配置方式1、package方式指定包路径:<mappers><packagename="org.snails.mapper"/></mappers>2、resource方式指定mapper.xml文件的相对路径:<map......
  • 视频直播源码,js控制滚动条位置
    视频直播源码,js控制滚动条位置今天遇到一个问题,scrollTop定位滚动条位置时不生效,查找问题发现在给元素设置滚动属性后,直接设置了该元素滚动条的位置,导致该元素没有子元素......
  • Mybatis缓存
    1.一级缓存同一个SqlSession对象第一次执行查询语句,把结果写入一级缓存之后没有更新插入删除操作,执行相同的查询语句,会读取一级缓存内数据1.1原理SqlSession级别的缓......
  • 【Spring 源码学习系列】BeanNameAware#setBeanName 方法的调用时机
    一、背景前一节我们研究了​​《ApplicationContextAware方法的调用时机》​​,对IOC容器最核心的方法refresh有了初步的了解。这节,我们将借助BeanNameAware方法的......
  • mybatis返回集合对象包含List<String>
    mybatis返回集合对象包含List<String>时间:2021-07-13本文章向大家介绍mybatis返回集合对象包含List<String>,主要包括mybatis返回集合对象包含List<String>使用实例、应用......
  • 在IDEA搭建JDK8源码运行环境
    源码的代码里会有很多的引用,我们只是单纯的用文本阅读,效率和体验都很不好,也不能使用debug功能查看每一步的代码执行效果,所以就需要借助idea编辑器工具,可以使用快捷键跳转到......
  • 【Java】Mybatis Plus LambdaQueryWrapper梳理
    【Java】Mybatis-PlusLambdaQueryWrapper梳理前言为了更方便的实现动态SQL,MybatisPlus在其基础上扩展了LambdaQueryWrapper,LambdaQueryWrapper提供了​​更加简便的查......
  • Tars-Java网络编程源码分析
    作者:vivo互联网服务器团队-JinKai本文从JavaNIO网络编程的基础知识讲到了Tars框架使用NIO进行网络编程的源码分析。一、Tars框架基本介绍Tars是腾讯开源的支持多语言的......
  • mybatis-plus的${ew.sqlSegment},${ew.sqlSelect},${ew.sqlSet},${ew.customSqlSegment}
    说明:ew是mapper方法里的@Param(Constants.WRAPPER)WrapperqueryWrapper对象1、${ew.customSqlSegment}会直接在前面添加where@Select(select*fromsys_user${ew.cust......
  • 悬赏任务app源码(uniapp小程序源码)成品平台搭建及开发
    悬赏任务app源码,从名字本身就可以理解这个PHP项目的流程。通过在线管理员工任务。即使它也可以在Intranet中工作。MySQL数据库是此源代码的最终部分。它易于实施和遵循。它......