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

有时候,不是因为你没有能力,也不是因为你缺少勇气,只是因为你付出的努力还太少,所以,成功便不会走向你。而你所需要做的,就是坚定你的梦想,你的目标,你的未来,然后以不达目的誓不罢休的那股劲,去付出你的努力,成功就会慢慢向你靠近。

导读:本篇文章讲解 Mybatis源码解析(五):SqlSession会话的创建,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

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<String, Statement> ,每次编译完成的 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);
}

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

  • 通过环境对象创建事务对象
  • 创建执行器对象
  • 由执行器及其他参数构建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、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;
  ...
}

在这里插入图片描述

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);
  }
}

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;
}

进入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);
  }

  ...
  
}

总结

  • 创建SqlSession会话对象这一步是一个承上启下的作用,利用上几步解析xml的对象构建以后执行sql的执行器
  • sql的执行及会话的关闭等核心代码都在执行器中,具体内容后面篇幅再讲

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148596.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!