1 概述
前面我们分析了一些Sql解析过程中的一些重要类(Executor、StatementHandler等)的源码,现在就需要对将这些类串起来的流程进行一个详细的分析,所以我们现在来分析一下Mybatis中Sql执行的流程。
2 流程图
从流程图我们大致将Sql执行分成四步,针对第一步在前面的文章中我们已经有过分析,所以现在我们就对后面三步进行深入分析。
3 流程分析
在这里我们首先上一段测试代码,这样方便结合上面的流程图进行理解。
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.findUserInfo("liubei");
我们首先来看第二步,调用openSession函数获得SqlSession。
3.1 获取SqlSession
在这里实际上是调用的SqlSessionFactory的实现类DefaultSqlSessionFactory的openSession函数。
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
这个方法里面直接调用openSessionFromDataSource函数来生成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);
//生成并返回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)获取环境对象
public Environment getEnvironment() {
return environment;
}
这里直接将读取配置文件初始化Configuration的时候生成的Environment进行返回就行了。
(2)获取事务工厂
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
//获取事务工厂
if (environment == null || environment.getTransactionFactory() == null) {
return new ManagedTransactionFactory();
}
return environment.getTransactionFactory();
}
针对事务工厂这里简单说明一下,我会用另外的博文对Mybaits事务处理这一块内容进行详细说明。
Mybatis的事务处理这里的设计使用了抽象工厂的设计模式。拥有两种事务工厂,ManagedTransactionFactory和JdbcTransactionFactory。可想而知,这两种事务工厂分别生成ManagedTransaction和JdbcTransaction两种事务处理类型。ManagedTransaction将事务处理交给程序的容器如(JBOSS,Weblogic),而JdbcTransaction则由JDBC来处理事务。
这里如果Mybatis配置文件中没有指定事务的类型,则使用ManagedTransactionFactory,如果指定为“JDBC”,则使用JdbcTransactionFactory。
(3)生成事务
这里就不进行详细说明了,可想而知这里其实就行对事务Transaction的基础内容进行设置,例如Connection、TransactionIsolationLevel。
(4)获取执行器
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;
}
所有的Mybatis语句都是通过执行器来完成的,所以这一步相当重要。
(5)生成并返回SqlSession
这一步其实就是调用构造函数DefaultSqlSession来生成SqlSession。
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
3.2 获取Mapper接口的动态代理对象
这里我们直接从DefaultSqlSession的getMapper函数开始查看。
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
可以看见,这里实际上调用的是Configuration的getMapper函数。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
而这个函数又是调用的MapperRegistry的getMapper函数,看来动态代理就是在MapperRegistry的getMapper函数中可以看见啊。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//获取到mapper代理工厂
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//获得并返回代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
前面的文章我们提到过MapperProxyFactory的作用其实就是生成Mapper接口的动态代理对象。