Mybatis源码 - sqlSessionFactory.openSession()方法解析 创建事务对象 装饰器模式创建执行器

前言

在Mybatis源码中,SqlSession是一个非常重要的类,它是数据库操作执行的开始。它的创建是通过接口SqlSessionFactory的实现类来创建的,默认是DefaultSqlSessionFactory。今天就来总结一下SqlSession对象的创建方法:openSession的执行流程与细节,自己进行复习的同时,也希望可以帮到大家。

正文

ExecutorType

因为SqlSessionFactory默认使用的子类是DefaultSqlSessionFactory,所以先来看一下它的源码:

java 复制代码
public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;
    
    @Override
    public SqlSession openSession() {
        return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
    }
}

可以看出openSession继续调用一个本类方法openSessionFromDataSource,顾名思义从数据源获取SqlSession,先看一下这个方法的入参,有下面三个

  1. ExecutorType:执行器类型
  2. TransactionIsolationLevel:事务隔离级别。
  3. boolean autoCommit:是否进行事务的自动提交。
java 复制代码
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    //。。。
  }

ExecutorType的赋值,调用了全局配置对象Configuration的getDefaultExecutorType()方法,点开可以发现,其实就是获取了defaultExecutorType这个属性的值,它的默认值是ExecutorType.SIMPLE

java 复制代码
public class Configuration {
    //省略其它代码...
    protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
    
    public ExecutorType getDefaultExecutorType() {
        return defaultExecutorType;
    }
}

ExecutorType其实是一个枚举类,里边定义了执行器的类型

java 复制代码
public enum ExecutorType {
    SIMPLE, REUSE, BATCH
}

openSessionFromConnection

这个方法就是真正创建SqlSession对象的方法,下面是它的源码:

java 复制代码
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);
        final Executor executor = configuration.newExecutor(tx, execType);
        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();
    }
}

第4-6行:先从全局配置对象获取了环境配置信息,然后通过调用getTransactionFactoryFromEnvironment方法从环境配置中获取了事务工厂对象,这个地方获取的事务工厂对象,跟xml中声明transactionManager时配置的别名type有关,获取到事务工厂对象之后,通过newTransaction方法创建了事务对象。

第7行通过调用全局配置对象的newExecutor方法完成了执行器Executor的创建,源码如下:

java 复制代码
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);
    }
    if (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

第5-11行:根据ExecutorType的值,创建了不同类型的执行器。

第12-14行:当框架开启了缓存的时候,返回的执行器为CachingExecutor,这里应用了一个装饰器模式,没有去修改原有执行的代码,而是包装了一层,在这里动态拓展了缓存相关的功能。

装饰器模式,在Mybatis加载配置文件时,对类加载器的获取的使用等,也应用了装饰器模式(可见 Mybatis源码 - 初始化流程 加载解析配置文件),加载配置文件时对类加载器的包装,并未去直接继承类加载器(ClassLoader),只是封装了一些加载资源时,加载器的获取、加载过程、判断、异常处理等过程,用来简化使用。

这里的应用略有不同,这里是使用了一个实现类CachingExecutor实现了Executor接口,并且使用一个属性来保存了其它执行器的引用,从结构上,更符合下面这张装饰器模式架构图:

第15行:是和Mybatis插件相关的代码,如果当前有配置的插件,这里会通过pluginAll方法,来创建一个代理对象,后续可以使用代理对象来实现插件的逻辑。

DefaultSqlSession

方法的最后,创建了DefaultSqlSession对象并返回,这就是openSession方法最后返回的实例。创建的同时,也将全局配置对象、执行器对象,是否自动提交标识进行了传递封装。

java 复制代码
return new DefaultSqlSession(configuration, executor, autoCommit);
相关推荐
qq_297574674 小时前
【实战教程】SpringBoot 集成阿里云短信服务实现验证码发送
spring boot·后端·阿里云
韩立学长5 小时前
【开题答辩实录分享】以《智能大学宿舍管理系统的设计与实现》为例进行选题答辩实录分享
数据库·spring boot·后端
编码者卢布8 小时前
【Azure Storage Account】Azure Table Storage 跨区批量迁移方案
后端·python·flask
tb_first9 小时前
SSM速通3
java·jvm·spring boot·mybatis
她说..10 小时前
策略模式+工厂模式实现审批流(面试问答版)
java·后端·spring·面试·springboot·策略模式·javaee
tb_first11 小时前
SSM速通4
java·jvm·spring·tomcat·maven·mybatis
梦梦代码精11 小时前
开源、免费、可商用:BuildingAI一站式体验报告
开发语言·前端·数据结构·人工智能·后端·开源·知识图谱
程可爱11 小时前
springboot整合mybatis和postgresql
spring boot·postgresql·mybatis
李慕婉学姐12 小时前
【开题答辩过程】以《基于Spring Boot的疗养院理疗管理系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·spring boot·后端
risc12345612 小时前
【Elasticsearch】LeafDocLookup 详述
大数据·elasticsearch·mybatis