前言
在Mybatis源码中,SqlSession是一个非常重要的类,它是数据库操作执行的开始。它的创建是通过接口SqlSessionFactory的实现类来创建的,默认是DefaultSqlSessionFactory。今天就来总结一下SqlSession对象的创建方法:openSession的执行流程与细节,自己进行复习的同时,也希望可以帮到大家。
正文
ExecutorType
因为SqlSessionFactory默认使用的子类是DefaultSqlSessionFactory,所以先来看一下它的源码:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
}
可以看出openSession继续调用一个本类方法openSessionFromDataSource
,顾名思义从数据源获取SqlSession
,先看一下这个方法的入参,有下面三个
- ExecutorType:执行器类型
- TransactionIsolationLevel:事务隔离级别。
- boolean autoCommit:是否进行事务的自动提交。
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
//。。。
}
ExecutorType的赋值,调用了全局配置对象Configuration的getDefaultExecutorType()方法,点开可以发现,其实就是获取了defaultExecutorType
这个属性的值,它的默认值是ExecutorType.SIMPLE
public class Configuration {
//省略其它代码...
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
public ExecutorType getDefaultExecutorType() {
return defaultExecutorType;
}
}
ExecutorType其实是一个枚举类,里边定义了执行器的类型
public enum ExecutorType {
SIMPLE, REUSE, BATCH
}
openSessionFromConnection
这个方法就是真正创建SqlSession对象的方法,下面是它的源码:
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的创建,源码如下:
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方法最后返回的实例。创建的同时,也将全局配置对象、执行器对象,是否自动提交标识进行了传递封装。
return new DefaultSqlSession(configuration, executor, autoCommit);