MyBatis源码解析系列(三)--从诞下SqlSession说起
上一篇MyBatis源码解析系列中,我们说完了SqlSessionFactory的诞生过程。这一篇中,我们要根据SqlSessionFactory工厂去得到SqlSession。那么,在这个过程中,究竟做了些什么?我们一一去解读。
一、SqlSession怎么来的
SqlSession是一个接口类,继承了Closeable(只有一个从AutoCloseable接口类继承来的方法close)。在SqlSession接口类中,提供了各种查询、删除、更新、提交、回滚等等方法。我们看类图:

既然是个接口类,那么总要有实现类去做这些事情,才能显示出接口类的价值。那么SqlSession是怎么来的?实现类是谁?
在篇二中,我们得到了SqlSessionFactory,它的默认实现类是DefaultSqlSessionFactory,既然是工厂实现类,那么DefaultSqlSessionFactory这里就是生产SqlSession的工厂车间。从这里,我们就可以找到SqlSession的来源。我们去看看。

从类图中我们可以看到,DefaultSqlSessionFactory提供了很多openSession方法,返回的对象类型就是SqlSession。
我们看下源码,源码中分为两种方式生产SqlSession,一种是使用方法private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit),一种是使用重载的private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection)。
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
public SqlSession openSession(boolean autoCommit) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}
public SqlSession openSession(ExecutorType execType) {
return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, false);
}
public SqlSession openSession(TransactionIsolationLevel level) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), level, false);
}
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return this.openSessionFromDataSource(execType, level, false);
}
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, autoCommit);
}
public SqlSession openSession(Connection connection) {
return this.openSessionFromConnection(this.configuration.getDefaultExecutorType(), connection);
}
public SqlSession openSession(ExecutorType execType, Connection connection) {
return this.openSessionFromConnection(execType, connection);
}那我们就分开来看下这两方法。
1、private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit):
源码如下:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}我们一行行来解释。结合我们的debug过程。
①在Environment environment = this.configuration.getEnvironment();中,根据我们在得到SqlSessionFactory过程中设置的对象configuration来获取在解析<element>元素时候设置的环境信息environment,设置后的信息如下:

②在TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);中,根据environment环境信息去获取environment对象中的TransactionFactory,这里是JdbcTransactionFactory,源码如下:
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
return (TransactionFactory)(environment != null && environment.getTransactionFactory() != null ? environment.getTransactionFactory() : new ManagedTransactionFactory());
}③在tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);中,使用transactionFactory工厂类去获取Transaction,这里传了三个参数,一是environment的数据源信息,一个是隔离级别,一个是是否自动提交的标识。我们看下这个newTransaction---构造Transaction的方法源码,这个方法的实现在JdbcTransactionFactory类中:
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}这里又使用了JdbcTransaction类的构造函数:
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
this.dataSource = ds;
this.level = desiredLevel;
this.autoCommmit = desiredAutoCommit;
}这样,获取到的Transaction就是JdbcTransaction。设置的信息如下,来个图看的更明白些:

④在 Executor executor = this.configuration.newExecutor(tx, execType);中,使用Transaction和execType来获取执行器,那这里的execType是啥玩意?这个就是在解析核心配置文件的<setting>标签时(方法在XMLConfigBuilder类中的settingsElement解析方法中),如<setting name="defaultExecutorType" value="SIMPLE"/>,会设置在configuration对象中,不同的execType标识不同的含义。它的取值有三个(SIMPLE, REUSE ,BATCH),含义分别如下:
SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。不设置时候默认使用SIMPLE,就是普通的执行器。我们这里使用的默认。
newExecutor方法源码如下:
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? this.defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object 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 (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}那我们这里得到的Executor经过判断就是SimpleExecutor了。
⑤在 var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);中,我们要去获取SqlSession的实现类了DefaultSqlSession,终于到了最后。源码如下:
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}这样,SqlSession的实现类DefaultSqlSession就拥有了配置对象信息,拥有了执行器信息,那么它就知道怎么去处理sql语句了。看看,这个configuration对象贯穿始终,核心的核心,源码是不会骗人的。
2、在private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection)方法中,它的源码如下:
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
DefaultSqlSession var8;
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException var13) {
autoCommit = true;
}
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
Transaction tx = transactionFactory.newTransaction(connection);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var14, var14);
} finally {
ErrorContext.instance().reset();
}
return var8;
}与上一个方法唯一的不同点在于,它传递了Connection 类的对象,这个对象用来获取autoCommit属性的值,其他跟上一个方法一模一样,我们不再赘述。
二、综上所述
上面就是获取SqlSession的所有步骤,是不是很简单?这就是源码,理解了原理,以后谁问也不怕。
下一帖,我们就要通过SqlSession去执行getMapper方法了,很期待。