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);
相关推荐
㳺三才人子5 小时前
初探 Flask
后端·python·flask·html
星栈独行5 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Java爱好狂.6 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易6 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
装不满的克莱因瓶7 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl7 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
excel8 小时前
为什么我推荐使用 Termius:现代 SSH 工具的完整体验
前端·后端
卷毛的技术笔记8 小时前
Java后端硬核实战:用Spring AI Alibaba+Redis给LLM装上“超强记忆中枢”
java·人工智能·redis·后端·spring·ai·系统架构
IT_陈寒9 小时前
Java的Optional差点让我掉坑里,这几个坑你别踩
前端·人工智能·后端
子兮曰10 小时前
Harness 驾驭工程深度教程:从 AGENTS.md 到全链路 AI 编码基础设施
前端·后端·ai编程