MyBatis 源码分析之 SqlSession 创建
创始人
2024-01-30 03:59:24
  • 三哥

内容来自【自学星球】

欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。

想要了解更多,欢迎访问👉:自学星球

该文章的内容有视频讲解,地址👉:点我直达

一、SqlSession的创建过程

SqlSession是mybatis的核心接口之一,是myabtis接口层的主要组成部分,对外提供了mybatis常用的api。myabtis提供了两个SqlSesion接口的实现,常用的实现类是DefaultSqlSession,它相当于一个数据库连接对象,在一个SqlSession中可以执行多条SQL语句。

前面我们已经分析等到了 SqlSessionFactory ,下面我们再来看看通过它如何拿到 SqlSession 。

// 获得会话;
SqlSession session = sqlSessionFactory.openSession();

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()

public SqlSession openSession() {// 第一个参数解释:configuration.getDefaultExecutorType(),获取了默认的执行器类型 SIMPLEreturn openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource

/*** ExecutorType 指定Executor的类型,分为三种:SIMPLE, REUSE, BATCH,默认使用的是SIMPLE* TransactionIsolationLevel 指定事务隔离级别,使用null,则表示使用数据库默认的事务隔离界别* autoCommit 是否自动提交,传过来的参数为false,表示不自动提交*/
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);// 创建Executor,即执行器// 它是真正用来Java和数据库交互操作的类,后面会展开说。final Executor executor = configuration.newExecutor(tx, execType);// 创建DefaultSqlSession对象返回,其实现了SqlSession接口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. 首先从 configuration 获取 Environment 对象,里面主要包含了 DataSource 和 TransactionFactory 对象。
  2. 创建 TransactionFactory
  3. 创建 Transaction
  4. 从 configuration 获取 Executor
  5. 构造 DefaultSqlSession 对象

我们先来看看常规的 environment 配置

//配置environment环境
/** 事务配置 type= JDBC、MANAGED *  1.JDBC:这个配置直接简单使用了JDBC的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。*  2.MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。*//** 数据源类型:type = UNPOOLED、POOLED、JNDI *  1.UNPOOLED:这个数据源的实现是每次被请求时简单打开和关闭连接。*  2.POOLED:这是JDBC连接对象的数据源连接池的实现。 *  3.JNDI:这个数据源的实现是为了使用如Spring或应用服务器这类的容器*///默认连接事务隔离级别 

environment 配置的解析在 2.1.5 节有分析。

再 environment 配置中 transactionManager type=“JDBC” 和 dataSource type=“POOLED” ,则生成的transactionManager 为 JdbcTransactionFactory,DataSourceFactory 为 PooledDataSourceFactory 。

回到 openSessionFromDataSource 方法,接着看看 getTransactionFactoryFromEnvironment 源码。

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#getTransactionFactoryFromEnvironment

private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {if (environment == null || environment.getTransactionFactory() == null) {return new ManagedTransactionFactory();}return environment.getTransactionFactory();
}

1.1 创建Transaction

tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory#newTransaction(javax.sql.DataSource, org.apache.ibatis.session.TransactionIsolationLevel, boolean)

public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {return new JdbcTransaction(ds, level, autoCommit);
}

直接通过工厂方法创建了一个JdbcTransaction对象,并传参DataSource ,事务隔离级别null,自动提交false三个参数,我们来看看 JdbcTransaction 这个类。

public class JdbcTransaction implements Transaction {//数据库连接对象protected Connection connection;//数据库DataSourceprotected DataSource dataSource;//数据库隔离级别protected TransactionIsolationLevel level;// MEMO: We are aware of the typo. See #941//是否自动提交protected boolean autoCommmit;public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {//设置dataSource和隔离级别,是否自动提交属性//这里隔离级别传过来的是null,表示使用数据库默认隔离级别,自动提交为false,表示不自动提交dataSource = ds;level = desiredLevel;autoCommmit = desiredAutoCommit;}@Overridepublic Connection getConnection() throws SQLException {if (connection == null) {openConnection();}return connection;}//提交功能是通过Connection去完成的@Overridepublic void commit() throws SQLException {if (connection != null && !connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Committing JDBC Connection [" + connection + "]");}connection.commit();}}//回滚功能是通过Connection去完成的@Overridepublic void rollback() throws SQLException {if (connection != null && !connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Rolling back JDBC Connection [" + connection + "]");}connection.rollback();}}//关闭功能是通过Connection去完成的@Overridepublic void close() throws SQLException {if (connection != null) {resetAutoCommit();if (log.isDebugEnabled()) {log.debug("Closing JDBC Connection [" + connection + "]");}connection.close();}}//获取连接是通过dataSource来完成的protected void openConnection() throws SQLException {if (log.isDebugEnabled()) {log.debug("Opening JDBC Connection");}connection = dataSource.getConnection();if (level != null) {connection.setTransactionIsolation(level.getLevel());}setDesiredAutoCommit(autoCommmit);}
}

JdbcTransaction主要维护了一个默认autoCommit为false的Connection对象,对事物的提交,回滚,关闭等都是接见通过Connection完成的。

1.2 创建Executor

回到 openSessionFromDataSource 方法,看下面这行代码

// 创建Executor,即执行器
// 它是真正用来Java和数据库交互操作的类,后面会展开说。
final Executor executor = configuration.newExecutor(tx, execType);

org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)

//创建一个执行器,默认是SIMPLE
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor executor;//根据executorType来创建相应的执行器,Configuration默认是SIMPLEif (ExecutorType.BATCH == executorType) {executor = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {//创建SimpleExecutor实例,并且包含Configuration和transaction属性executor = new SimpleExecutor(this, transaction);}//如果要求缓存,生成另一种CachingExecutor,装饰者模式,默认都是返回CachingExecutor/*** 二级缓存开关配置示例* *   * */// cacheEnabled 默认为 trueif (cacheEnabled) {//CachingExecutor使用装饰器模式,将executor的功能添加上了二级缓存的功能,二级缓存会单独文章来讲executor = new CachingExecutor(executor);}//此处调用插件,通过插件可以改变Executor行为,此处我们后面有机会在分析executor = (Executor) interceptorChain.pluginAll(executor);return executor;
}

executor 包含了 Configuration 和刚刚创建的 Transaction,默认的执行器为 SimpleExecutor,如果开启了二级缓存(默认开启一级缓存),则 CachingExecutor 会包装 SimpleExecutor,然后依次调用拦截器的 plugin 方法返回一个被代理过的Executor对象。

executor 默认情况下就是 CachingExecutor ,只不过如果二级缓存没有开启,则实际还是调用 SimpleExecutor 去执行(CachingExecutor 包装了 SimpleExecutor 类型),后面会分析该类。

1.3 构造DefaultSqlSession对象

// 创建DefaultSqlSession对象返回,其实现了SqlSession接口
return new DefaultSqlSession(configuration, executor, autoCommit);

大致看一下 DefaultSqlSession 类

public class DefaultSqlSession implements SqlSession {/*** mybatis全局配置新*/private final Configuration configuration;/*** SQL执行器*/private final Executor executor;/*** 是否自动提交*/private final boolean autoCommit;private boolean dirty;private List> cursorList;public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {this.configuration = configuration;this.executor = executor;this.dirty = false;this.autoCommit = autoCommit;}// ...}

SqlSession的所有查询接口最后都归结位Exector的方法调用,后面在分析。

好了,今天的内容到这里就结束了,我是 【J3】关注我,我们下期见


  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。

  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。

  • 感谢您的阅读,十分欢迎并感谢您的关注。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
安徒生童话有哪些 安徒生童话的... 从德国汉堡港乘轮船渡波罗的海抵丹麦王国,就到了安徒生的祖邦。安徒生(1805-1875)以童话作品闻...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
安徒生童话有哪些 安徒生童话的... 从德国汉堡港乘轮船渡波罗的海抵丹麦王国,就到了安徒生的祖邦。安徒生(1805-1875)以童话作品闻...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...