您的位置:首页 > 运维架构 > 网站架构

java架构之路-(源码)mybatis执行流程源码解析

2019-09-18 13:03 1451 查看

  这次我们来说说Mybatis的源码,这里只说执行的流程,内部细节太多了,这里只能授之以渔了。还是最近的那段代码,我们来回顾一下。

package mybatis;

import mybatis.bean.StudentBean;
import mybatis.dao.StudentMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class Test1 {

public SqlSession session;
public SqlSessionFactory sqlSessionFactory;

@Before
public void init() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession();
}

@Test
public void studentTest() {
StudentMapper mapper = session.getMapper(StudentMapper.class);
StudentBean result = mapper.selectUser(1);
System.out.println(result);
session.commit();
}

}

就是拿到流文件,也是我们主配置文件,进行流文件解析,传入到build内,构建成一个sqlSessionFactory,再由sqlSessionFactory得到session,拿到mapper,执行sql,完成。

简单的流程应该是这样的,我们来一个稍微专业一点图。

 转变为我们的代码大概就是这三步,构建Configuration对象,构建我们的sqlsessionfactory,得到我们的session,得到对应的statement(处理参数和结果)从而得到结果集。

那么我们先从我们一步步来看,先看我们的Configuration对象

Configuration解析:

  我们打开Configuration类可以看到,里面很多的属性设置,包括缓存,mapper,插件等等,其实就是把我们的xml标签转化为对象了,这里需要说明一下的是,这个解析过程是把所有的相关的xml都转为Configuration对象了,包括config.xml和mapper.xml。源码太多,我就不粘贴了。我给你看一下我转化完成的。

 这里没有什么神秘的,就是一个xml解析的过程,在XMLConfigBuilder类的parse方法,生成了完成的Configuration对象,有兴趣的可以打个断点看一下。

 

 这里要注意的就是里面很多元素是一个对应多个的,很多属性是map和set。顺便收一下里面是由多个构造器来构建的。

 MapperAnnotationBuilder为注解方式的构造器,其余都是为Configuration服务的。也就是说在创建Configuration之后很多东西就已经确定了(除了cache)。那么又是如何生成sqlsession的呢。回到我们创建完Configuration对象那句源码上来。

点击build方法进去,我们看到是new DefaultSqlSessionFactory然后把我们的Configuration对象传递进去,也就是说有了Configuration对象也就生成了我们的DefaultSqlSessionFactory对象。DefaultSqlSessionFactory实现了我们的SqlSessionFactory,我们也就得到了SqlSessionFactory。接下来就是我们的sqlsession了

sessionsql解析:

  还是老规矩,上个图再看源码,比较好理解。

 

 

 执行过程大概是这样的。

 就是什么意思呢?由DefaultSqlSessionFactory生成一个执行器Executor,下面是由BaseExecutor支撑的,里面包含一些配置和我们的一级缓存(是不是更深入的知道为啥一级缓存生命短了),同时也有一个类似装饰器的CachingExecutor,他的下面也是需要BaseExecutor来支撑的,需要查询时优先查缓存,查询不到回到我们的BaseExecutor来执行。搂一眼源码去,sqlSessionFactory.openSession()方法也就得到了我们的sqlsession,我们进去看一下都写了什么。

里面的95行tx主要是从我们的configuration中拿到一些数据源的配置,也就是我们图中画的来支撑BaseExecutor的配置,来到96行,创建Executor,传入了数据源配置和一个执行类型,这里简单提一嘴,类型主要有三种:SIMPLE(简单), REUSE(可重复使用), BATCH(批量进行),一般我们都用的SIMPLE。我们再进我们的Executor的创建方法看看,他们都做了什么事。

 先判断了执行器类型,简单,可重复,批量,613行就是我们的缓存执行器了,外面那个判断就是你是否配置了二级缓存,从而是否配置我们的缓存执行器,底层还是Executor,可以点击进去看看的。

就是说我们由配置文件config.xml,mapper.xml生成了我们的Configuration对象,将Configuration放置在DefaultSqlSessionFactory内,生成了我们的Executor执行器,准备执行SQL。回到主题我们继续看下一部分,最后一个MappedStatement

MappedStatement解析:

  记住两个问题,增删改查,可以归类为两种,一种是原来的数据变化-增删改,另一种是原来的数据没有变化-查询。我们的mybatis也是这样来处理的,主要就是query和update两种大类方法。

  MappedStatement是由调用Executor执行器前,由configuration对象来构建的。源码在DefaultSqlSession的select***方法内,这里就不详细说了。感兴趣的可以自己去了解一下。我们主要来说执行流程。

  执行过程大致是,1.拿到sql;2.拼接参数;3.执行sql;4.封装结果集。我们来看一下具体的源码流程。

  我们上面得知,执行器的真正执行都是在BaseExecutor里来执行的,我们在DefaultSqlSession调用的select方法,最后执行了executor.query,只优先走我们的CachingExecutor执行器,如果没有才到我们的BaseExecutor执行器里面来,我们的sql是查询,不需要变动数据,那么我们把断点打在我们的BaseExecutor类的query方法上。

147行是清理我们的一级缓存,如果在mapper.xml配置了清理标签,这里会先清理一级缓存。queryStack表示这个执行器是否正在被使用。

152行开始查询我们的一级缓存,如果为空调用156行,开始我们正式的查询,里面是放入缓存占位置,然后执行查询,清理缓存的占位重新放置缓存,这里说的都是一级缓存了。

 

总结一下就是:

1.拿到流文件config.xml和mapper.xml;

2.用我们的两个或多个流文件创建一个Configuration对象,(单一职责原则来构建的,很多个构造器来构建的,例如XMLConfigBuilder)

3.将Configuration对象塞给SqlSessionFactoryBuilder类的build方法,构建SqlSessionFactory对象。

4.sqlSessionFactory.openSession()拿到我们的session对象。

5.由session对象和Configuration对象封装参数和结果集映射,产生对应的执行器来,二级缓存执行器和BaseExecutor执行器。

6.由二级缓存执行器CachingExecutor来优先查询二级缓存是否存在,不存在执行BaseExecutor执行器的query或update方法。

7.拿到结果集转换ResultMap,session关闭,写入二级缓存,返回结束。

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: