『手撕 Mybatis 源码』04 - 创建 sqlSession

创建 sqlSession

创建 openSession 对象

  1. 当获取 SqlSessionFactory 之后,就可以开始获取 SqlSession 对象
public class MybatisTest {

  @Test
  public void test1() throws IOException {
  ...
    // 3.问题:openSession()执行逻辑是什么?
    // 3. (1) 创建事务对象 (2)创建了执行器对象cachingExecutor (3)创建了 DefaultSqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    ...
    sqlSession.close();
  }
}
  • 其中,openSession() 支持很多种参数类型定义,主要是判断是否进行事务自动提交、数据库连接、执行器类型选择、事务隔离级别
    在这里插入图片描述
  1. 下面是走默认构造函数
public class DefaultSqlSessionFactory implements SqlSessionFactory {
	// Configuration 是 Factory.build() 的时候,封装到这里
	private final Configuration configuration;
   ...
  @Override
  public SqlSession openSession() {
    // 调用 openSessionFromDataSource 
    // 参数 1:执行器类型  
    // 参数 2:事务隔离级别
    // 参数 3:指定事务是否自动提交,默认是 false
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
}
  • 其中,getDefaultExecutorType() 返回默认执行器类型,也就是 SIMPLE
public class Configuration {
  ...
  // 默认执行器类型
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  ...
  public ExecutorType getDefaultExecutorType() {
    return defaultExecutorType;
  }
}
  • 执行器类型包含 SIMPLEREUSEBATCH,实现的类图如图下所示
    在这里插入图片描述
    • BaseExecutor:基础执行器,封装了子类的公共方法,包括一级缓存、延迟加载、回滚、关闭等功能
    • SimpleExecutor:简单执行器,每执行一条 sql,都会打开一个 Statement,执行完成后关闭
    • ReuseExecutor:重用执行器,相较于 SimpleExecutor 多了 Statement 的缓存功能,其内部维护一个 Map<String, Statement> ,每次编译完成的 Statement 都会进行缓存,不会关闭
    • BatchExecutor:批量执行器,基于 JDBC 的 addBatch()executeBatch() 功能,并且在当前 sql 和上一条 sql 完全一样的时候,重用 Statement,在调用doFlushStatements() 的时候,将数据刷新到数据库
    • CachingExecutor:缓存执行器,装饰器模式,在开启缓存的时候。会在上面三种执行器的外面包上 CachingExecutor
  1. openSessionFromDataSource 中,先拿到 environment 对象,根据 environment 对象里面的配置、包括数据源,创建事务工厂对象。然后根据执行器类型,利用事务管理器创建 executor 对象,最后把 configurationexecutor 封装到 DefaultSqlSession 返回
public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;
  ...
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 从 configuration 对象中获取 environment 对象
      // environment 里面封装 dataSource 和 事务工厂(即配置文件上写的 type="JDBC")时候创建的
      final Environment environment = configuration.getEnvironment();
      // 获得事务工厂对象
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 构建事务对象
      // 看类型,才决定用哪个工厂,因为 xml 写的是 JBBC,所以用 JdbcTransactionFactory。如果是 Managed 就是交给容器来管理事务
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 创建执行器对象
      final Executor executor = configuration.newExecutor(tx, execType);
      // 创建 DefaultSqlSessio n对象
      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. JdbcTransactionFactorynewTransaction() 中,会返回一个 JdbcTransaction 对象,它的底层会通过一个 Connection 对象,进行 commit() 或者 rollback()
public class JdbcTransactionFactory implements TransactionFactory {
  ...
  @Override
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }
}
  1. 在使用 sqlsession 时,具体的执行是依赖执行器的,下面看看执行器的创建。根据传入的执行器类型,来对 transaction 进行封装,如果开启了 cacheEnabled 还会利用装饰者模式,对创建的 executor 再包一层,开启缓存。最后还可以使用拦截器插件也再对 executor 进行封装
public class Configuration {
  ...
  // 默认执行器类型
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  // 是否启用缓存
  protected boolean cacheEnabled = true;
  ...
  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) { // 默认 true
      executor = new CachingExecutor(executor);
    }
    // 拦截器插件
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
}
  1. 总结
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值