这一篇文章主要MyBatis拿到配置文件之后,即获取到数据源配置信息和SQL语句之后,然后再从源码解读分析MyBatis是如何进行数据库连接和SQL语句执行。关于MyBatis是如何解析mybatis-config.xml文件,获取到数据源的请看这篇文章:
1、背景介绍
根据官网介绍结合自己的理解,MyBatis的流程图如下所示:
根据流程图,在上篇文章中创建了一个测试类,并且详细介绍了MyBatis是如何解析配置文件,获取到数据源信息及SQL语句的。下面来看一下上一篇文章中的测试类:
public class TestMyBatis {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
//获取MyBatis配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
//通过SqlSessionFactoryBuilder的build()方法获取SqlSessionFactory 对象
//此时已将MyBatis配置文件的相关配置已获取到,即Configuration类已获取到值
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过SqlSessionFactory的openSession()方法获取SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//通过SqlSession对象执行SQL语句
List<BaseUserInfoDO> result = sqlSession.selectList("com.mybatis.DemoMapper.queryBaseUserInfoDO");
System.out.println(result.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}
其中下面的语句的已在上篇文章中详细解析过了。
//已解析
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
因此本篇文章主要解析以下语句,来探查MyBatis底层是如下进行数据库连接和执行SQL语句的。
//创建SQL会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行SQL查询语句
List<BaseUserInfoDO> result = sqlSession.selectList("com.mybatis.DemoMapper.queryBaseUserInfoDO");
2、创建SqlSession
创建SqlSession其实就是根据Confiuration对象实例化一个SQL执行器,一个执行器里面需要包含数据源信息和事务管理器,然后根据Confiuration对象和实例化的SQL执行器创建一个SqlSession对象,数据库连接和SQL语句的执行都在这个SqlSession里面进行操作。
创建SqlSession对象的执行语句如下所示:
//已解析结束
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//根据sqlSessionFactory对象创建一个SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
其中openSession() 方法的源码如下图所示,已省略无关代码:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
//openSession()方法的入口
public SqlSession openSession() {
//调用openSessionFromDataSource()方法创建一个SqlSession对象
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
/**
* 此方法就是根据之前的configuration对象获取数据源信息,
* 然后根据数据源信息和配置的事务管理器类型新建一个JDBC事务管理器,
* 然后根据新建的事务管理器和配置的执行器类型新建一个SQL执行器,
* 随后根据configuration和执行器实例化一个SqlSession 对象
**/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
//新建一个事务管理器
Transaction tx = null;
try {
//获取Environment对象,里面包含数据源信息和事务管理器类型
final Environment environment = configuration.getEnvironment();
//获取事务管理器工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//根据数据源信息和事务管理器类型实例化一个JDBC事务管理器对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//根据事务管理器和执行器类型,实例化一个SQL执行器。执行器类型为Simple类型
final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
//创建一个SqlSession对象返回
return new DefaultSqlSession(configuration, executor);
} 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()方法的源码,可以从源码上了解SQL执行器的初始化过程,无关代码已省略。
public class Configuration {
//newExecutor()方法的入口
public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
//判断执行类型是否为空,如果为空,则赋值为默认的执行器类型,否则执行器类型不做改变
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
//初始化一个执行器
Executor executor;
//根据配置的执行器类型,实例化一个执行器
//这里可以看到共有三种执行器类型,分别为BATCH、REUSE、SIMPLE
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) {
//如果开启,则缓存中的SQL执行器也被设置为当前执行器类型
executor = new CachingExecutor(executor, autoCommit);
}
//设置拦截器,就是在进行SQL语句执行之前可以在拦截器中做一些SQL语句方面的修改
executor = (Executor) interceptor