阅读完需:约 7 分钟
SqlSession的构建过程
在上一章,详细的介绍了SqlSessionFactory的构建过程,它是用来获取SqlSession对象的,所以本章节就主要讲述SqlSession的构建过程。
程序代码的入口:

我们知道SqlSession
对象是通过SqlSessionFactory
的openSession()
方法获取的,所以我们先来看一下SqlSessionFactory
接口中的方法:

public interface SqlSessionFactory {
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);
Configuration getConfiguration();
}
可以发现SqlSessionFactory
接口提供一系列重载的openSession
方法,其参数如下(这些参数的意义会在后面介绍):
- boolean autoCommit:是否开启JDBC事务的自动提交,默认为false。
- Connection:提供连接。
- TransactionIsolationLevel:定义事务隔离级别。
- ExecutorType:定义执行器类型。
SqlSessionFactory
接口的实现类为DefaultSqlSessionFactory
类。所以我们去DefaultSqlSessionFactory
实现类中查看重写的openSession()方法:
//以无参的openSession()方法为例
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
通过查看其它重写的方法,会发现最终都调用了openSessionFromDataSource
方法,所以继续进入方法:
/**
* 方法实现说明:从session中开启一个数据源
* @author:xsls
* @param execType:执行器类型
* @param level:隔离级别
* @return:SqlSession
* @exception:
* @date:2019/9/9 13:38
*/
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);
/**
* 创建一个sql执行器对象
* 一般情况下 若我们的mybaits的全局配置文件的cacheEnabled默认为ture就返回
* 一个cacheExecutor,若关闭的话返回的就是一个SimpleExecutor
*/
final Executor executor = configuration.newExecutor(tx, execType);
/**
* 创建返回一个DeaultSqlSessoin对象返回
*/
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();
}
}
上面代码中有一行是通过configuration.newExecutor(tx,execType)
来构建Executor
执行器对象,这一步非常重要,因为MyBatis 中所有的 Mapper 语句的执行都是通过 Executor 来执行的,它负责SQL语句的生成和查询缓存的维护 。所以我们看一下它是怎么创建的,这里调用了Configuration类中newExecutor()方法。
/**
* 方法实现说明:创建一个sql语句执行器对象
* @author:xsls
* @param transaction:事务
* @param executorType:执行器类型
* @return:Executor执行器对象
* @exception:
* @date:2019/9/9 13:59
*/
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 {
//简单的sql执行器对象
executor = new SimpleExecutor(this, transaction);
}
//判断mybatis的全局配置文件是否开启缓存
if (cacheEnabled) {
//把当前的简单的执行器包装成一个CachingExecutor
executor = new CachingExecutor(executor);
}
/**
* TODO:调用所有的拦截器对象plugin方法
*/
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
注意:executor = (Executor) interceptorChain.pluginAll(executor);
这个是Mybatis中的插件,它将构建一层层的代理对象,可以在执行真正的Executor的方法前,执行配置在插件中的方法对核心代码进行修改,所以不要轻易使用插件,这里用的是责任链模式。Mybatis在实例化Executor、ParameterHandler、ResultSetHandler、StatementHandler
四大接口对象的时候都是调用interceptorChain.pluginAll()
方法插入进去的。其实就是循环执行拦截器链所有的拦截器的plugin() 方法。
Executor分成两大类,一类是CacheExecutor
,另一类是普通Executor
。普通Executor又分为三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
-
SimpleExecutor
:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。 -
ReuseExecutor
:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。 -
BatchExecutor
:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。CacheExecutor其实是封装了普通的Executor,和普通的区别是在查询前先会查询缓存中是否存在结果,如果存在就使用缓存中的结果,如果不存在还是使用普通的Executor进行查询,再将查询出来的结果存入缓存。
Executor 对象创建完之后会以参数的形式传入DefaultSqlSession
的构造方法中,从而完成SqlSession对象的创建并且返回。

至此SqlSession对象的创建过程也就结束了
拿到SqlSession就可以执行各种CRUD方法了
SqlSession对象构建过程中的时序图:

重载的openSession方法参数介绍
上面程序入口我们调用的是无参数的openSession()
方法,那么其它重载的方法有什么用呢?这里来介绍一下有参方法中的参数含义,有四类分别为。
- boolean autoCommit:是否开启JDBC事务的自动提交,默认为false。
- Connection:提供连接。
- TransactionIsolationLevel:定义事务隔离级别。
- ExecutorType:定义执行器类型。
①、boolean autoCommit:是否自动提交事物,默认为false。
如果为true就自动提交事务,后面就不要写commit()方法提交了。
②、TransactionIsolationLevel :事务隔离级别类,它是一个枚举类型。

可以发现默认五种隔离级别:
- NONE(Connection.TRANSACTION_NONE):无隔离级别
- READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED):读取提交内容
- READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED):读取未提交内容
- REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ):可重复读
- SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE):可串行化
③、Connection:提供连接对象。
如果使用这种方式会优先使用这里面的数据库连接对象。如:

④、ExecutorType :执行器类型,它是一个枚举类型。

它主要用来判断使用哪种类型的执行器Executor,因为SqlSession是真正来执行Java与数据库交互的对象,提供了查询(query)、更新(update)等方法,主要有三种类型:
- SIMPLE:简易执行器,如果不配置类型,就是默认执行器
- REUSE:能过执行重用预处理语句的执行器
- BATCH:执行器重用语句和批量更新,批量专用的执行
在上面创建Executor执行器的代码中已经进行了判断。所以这里就不再多说了。

