Mybatis SqlSession 如果面试官问如何创建?

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: Mybatis SqlSession 如果面试官问如何创建?


阅读文章能够收获 SqlSessionFactoryBuilder, SqlSessionFactory、SqlSession 相关知识

为防止不必要的麻烦, 直接下载 3.4.x 版本的 mybatis 源码, 文章中测试代码是在 org.apache.ibatis.autoconstructor 目录下建立新的文件夹进行测试

01、相关概念简介
1.1 SqlSession
负责执行 select、insert、update、delete 等命令, 同时负责获取映射器和管理事务; 其底层封装了与 JDBC 的交互, 可以说是 mybatis 最核心的接口之一

SqlSession 非线程安全, 所以每个线程都拥有一个实例; 通俗来说来一个请求就打开一个对应的 SqlSession, 使用后进行关闭

在我们日常项目中基本都是使用 mybatis, spring 整合版, 生命周期和线程安全问题不需要考虑

1.2 SqlSessionFactory
负责创建 SqlSession 的工厂, 一旦被创建就应该在应用运行期间一直存在, 不需要额外再进行创建

平常项目中也是配置为 spring 中一个单例 bean

1.3 SqlSessionFactoryBuilder
主要是负责创建 SqlSessionFactory 的构造器类, 其中使用到了构建者设计模式; 创建 SqlSessionFactory 后就没啥子用了

在 spring 与 mybatis 的整合项目中, 构建 SqlSessionFactory 的任务交给了 SqlSessionFactoryBean, 在这里了解即可, 核心思想和处理结果是一致的

02、SqlSession 创建代码
下载源码之后, 在源码项目的 test目录 下面创建自己的测试包, 然后从文章底部获取 mybatis官网链接 复制创建 SqlSession 的代码, 粘贴运行即可

@Test
public void buildSqlSession() throws IOException {
    // mybatis-config.xml 文件路径
    String resource = "org/apache/ibatis/autoconstructor/mybatis-config.xml";
    // 根据 mybatis io 资源包下的工具类直接获取流
    InputStream inputStream = Resources.getResourceAsStream(resource);
    // 这里采用字节流构建 SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    // 通过 sqlSessionFactory 获取 sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    System.out.println(sqlSession);
}
下面会从 SqlSessionFactoryBuilder 、 SqlSessionFactory 、 SqlSession 按照创建关系进行解析

03、解析 SqlSessionFactoryBuilder
通过源码看出, build() 大部分重载方法基本围绕 Reader、InputStream 这两个对象, 真正构建会话工厂的方法为 build(Configuration config)

public SqlSessionFactory build(Reader reader)
public SqlSessionFactory build(Reader reader, String environment)
public SqlSessionFactory build(Reader reader, Properties properties)
public SqlSessionFactory build(Reader reader, String environment, Properties properties)
public SqlSessionFactory build(InputStream inputStream)
public SqlSessionFactory build(InputStream inputStream, String environment)
public SqlSessionFactory build(InputStream inputStream, Properties properties)
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
// 创建 SqlSessionFactory 的调用方法
public SqlSessionFactory build(Configuration config)
上面入参为 Reader 的 build() 也是通过 InputStream 创建的, 从字节流转换成了字符流

@Test
public void buildSelSessionByReader() throws IOException {
    final Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
字节流转换字符流方法

public static Reader getResourceAsReader(String resource) throws IOException {
    Reader reader;
    if (charset == null) {
        reader = new InputStreamReader(getResourceAsStream(resource));
    } else {
        reader = new InputStreamReader(getResourceAsStream(resource), charset);
    }
    return reader;
}
SqlSessionFactoryBuilder 大部分 build() 方法都是为了解析出 Configuration 对象

解析出Configuration 对象后开始创建 SqlSessionFactory, 可以看下具体实现

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}
04、解析 SqlSessionFactory
SqlSessionFactory 是一个接口并非具体的类, 其具体实现类是在 build(Configuration config) 方法中创建的 new DefaultSqlSessionFactory(config)

在实现类的构造方法中并无实际逻辑, 只是把 config 对象赋值给了内部变量 Configuration

public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
}
05、解析 SqlSession
通过 04 章节已经可以得到创建 SqlSession 的 SqlSessionFactory 对象了, 那么接下来就是要解析本篇的重头戏 SqlSession

SqlSessionFactory 接口中声明了一系列 opensession 方法,用来返回 SqlSession 对象

SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);

在实现类 DefaultSqlSessionFactory 中实现了接口中定义的方法, 如下

public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
说一下返回的 openSessionFromDataSource 方法, 重载的方法其实大致都一致, 这里挑典型说明

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();
    }
}
5.1 参数列表
1》执行器类型 ExecutorType

ExecutorType 是一个执行器类型枚举, 里面有三种类型 SIMPLE, BATCH, REUSE, 分别对应如下执行器

SimpleExecutor: 在每次执行完成后都会关闭 statement 对象, 为默认执行器

BatchExecutor: 会将修改操作记录在本地,等待程序触发或有下一次查询时才批量执行修改操作

ReuseExecutor: 会在本地维护一个容器,当前 statement 创建完成后放入容器中,当下次执行相同的 sql 时会复用 statement 对象,执行完毕后也不会关闭

2》TransactionIsolationLevel

TransactionIsolationLevel 代表了数据库的隔离级别, 也是一个枚举, 其中包含数据库的四种隔离级别

NONE: 没有隔离级别

READ_COMMITTED: 读取提交内容

READ_UNCOMMITTED: 读取未提交内容

REPEATABLE_READ: 可重复读

SERIALIZABLE: 可串行化

3》autoCommit

第三个参数为是否自动提交事务, 默认不自动提交

5.2 方法代码解析
读取 MyBatis-Config.xml 形成 Environment 对象

final Environment environment = configuration.getEnvironment();
根据 Environment 当作入参, 获取事务工厂

final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
事务工厂根据数据源, 数据库隔离级别, 是否自动提交事务标识创建事务对象

Transactiontx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
根据事务对象和不同的执行器类型创建不同的 Mybatis Executor, 通过这里可以得知, 事务和执行器是绑定的

final Executor executor = configuration.newExecutor(tx, execType);
SqlSession 也是一个接口, DefaultSqlSession 为默认实现类

根据全局配置对象, 执行器, 是否自动提交事务标识创建 DefaultSqlSession 对象

return new DefaultSqlSession(configuration, executor, autoCommit)
06、学习总结
在写这篇文章的时候, 构思的思路本来是挺清晰的, 但是越写感觉知识面越多, 所以只能把构建 SqlSession 主流程写出来

如果留心或者阅读过 mybatis 源码的同学应该能看出以下几项

不是我不写, 而是: 写出来就是另一个故事了, [捂脸]

参考资料
[1] Mybatis源码地址: https://github.com/mybatis/mybatis-3

[2] Mybatis官网地址: https://mybatis.org/mybatis-3

相关文章
|
6月前
|
缓存 Java 数据库连接
Mybatis缓存相关面试题有多卷
使用 MyBatis 缓存机制需要注意以下几点: 对于频繁更新和变动的数据,不适合使用缓存。 对于数据的一致性要求比较高的场景,不适合使用缓存。 如果配置了二级缓存,需要确保缓存的数据不会影响到其他业务模块的数据。 在使用缓存时,需要注意缓存的命中率和缓存的过期策略,避免缓存过期导致查询性能下降。
105 0
|
6月前
|
Java 关系型数据库 数据库连接
BATJ高频面试249道题:微服务+多线程+分布式+MyBatis +Spring
本文收集整理了各大厂常见面试题N道,你想要的这里都有内容涵盖:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等技术栈,希望大家都能找到适合自己的公司,开开心心的撸代码。
|
5月前
|
SQL 缓存 Java
MyBatis最经典的20道面试题,你都会了吗?
MyBatis最经典的20道面试题,你都会了吗?
68 0
|
6月前
|
SQL 缓存 Java
Mybatis面试题
Mybatis面试题
|
4月前
|
SQL Java 数据库连接
Mybatis之SqlSession简析
Mybatis之SqlSession简析
152 0
|
5月前
|
Java 数据库连接 mybatis
使用Mybatis获取sqlSession对象老爆红的问题解决
使用Mybatis获取sqlSession对象老爆红的问题解决
|
6月前
|
SQL Java 数据库连接
MyBatis之魂:探索核心接口SqlSession的神秘力量
MyBatis之魂:探索核心接口SqlSession的神秘力量
75 3
MyBatis之魂:探索核心接口SqlSession的神秘力量
|
6月前
|
存储 缓存 Java
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
|
6月前
|
SQL Java 数据库连接
一篇看懂Mybatis的SqlSession运行原理
SqlSession是Mybatis最重要的构建之一,可以简单的认为Mybatis一系列的配置目的是生成类似 JDBC生成的Connection对象的SqlSession对象,这样才能与数据库开启“沟通”,通过SqlSession可以实现增删改查(当然现在更加推荐是使用Mapper接口形式),那么它是如何执行实现的,这就是本篇博文所介绍的东西,其中会涉及到简单的源码讲解。
196 1
|
6月前
|
SQL Java 数据库连接
MyBatis常见面试题总结2
MyBatis常见面试题总结
53 0
下一篇
无影云桌面