MyBatis源码阅读

2021/7/25 11:40:40

本文主要是介绍MyBatis源码阅读,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1、前言

        本文关于mybatis的源码解读主要基于mybatis运行主流程。例如:config文件解析、xml解析生成sql语句以及sql语句的具体执行过程,不包含例如缓存、插件等源码。(有机会单独写。。。。)

<!-- 华丽的分割线 -->


2、基本结构

 

  • SqlSessionFactoryBuilder

解析所有配置文件,放到configure里头,生成SqlSessionFactry

  • SqlSessionFactry

没有特别需要介绍的,主要就是产生SqlSession。

  • SqlSession

用于执行sql语句的对象,其实真正执行sql的对象是SqlSession里的Executor对象。可以看到起内部doQuery,doUpdate等方法利用StatementHandler执行sql语句。

3、配置文件的解析

Configure —— 配置文件的解析

        SqlSessionFactoryBuilder会构建一个XMLConfigBuilder对象,他是BaseBuilder的子类,该对象会解析所有与Mybaties有关的xml文件,其中parse()方法的字方法parseConfiguratio()会解析所有xml文件,并填充到configuration对象里。(注意:该对象在BaseBuilder也就是XMLConfigBuilder的父类里)需要注意的一点是,该方法在每次启动项目后只会执行一次,XMLConfigBuilder的bollean属性parsed确保了这一点。另外,产生的configuration对象应该是全局唯一(单例),且无处不在的。因为其不光保存了mybatis-config.xml 里的基础配置,还保存了所有xxxMapper.xml文件里的信息。

 

 至此,所有xml文件解析完毕,configure里的内容填充好了

Configure重点对象

 

 

其中比较重点的对象:resultMaps , parameterMaps,mappedStatements

  • resultMaps

存储的是所有mapper.xml文件里的resultMap定意的内容,其中key是mapper.xml全路径名 + resultMap的id;value是ResultMap,里面存着result对应pojo属性列表,数据库表里对应的列名列表,以及属性和列的映射关系——ResultMapping。ResultMapping里有更详细的内容,比如,属性java类型是啥,column的数据库类型是撒等等。

  • parameterMaps

存储的是传入的参数映射。例如传入的查询条件对象等等就会存储到这里。又比如,新增的时候传入的pojo对象就会被分解为 属性—值得映射存在这里。

  • mappedStatements

保存的是MappedStatement,MappedStatement保存的是一个映射节点(select|update|insert),包含需要我们配置的sql(存在sqlSource里)、sql的id、ResultMap、parameterType等。MappedStatement里面还有一个重要的对象,SqlSource,他提供了BoundSql用于根据我们mapper的配置生成sql语句,因此其内部就会有两个重要的内容:1、基础语句,比如:select from where啥的,这部分是根据mapper配置文件产生的。2、生成的语句,是根据传入的POJO或parameterMap生成的。两者拼接就形成了需要的map语句。

注意:每一个映射节点,select|update|insert等等,都对应着一个MappedStatement存储在configure的mappedStatements里面。每一个MappedStatement都对应着一个SqlSource生成一个BoundSql用于生成sql语句。

SqlSource —— sql语句的解析

他是一个接口,实现它的类有四个,比较重要的是DynamicSqlSource,StaticSqlSource。

StaticSqlSource解析的是mapper里一些写死的sql。例如:

 DynamicSqlSource也就是动态SqlSource,是基于StaticSqlSource实现的。他是干什么的呢,用于生成动态sql的。比如,我们update里有很多<if></if>,<forEach></forEach>等等语句,这样就需要根据情况动态生成sql,就需要利用DynamicSqlSource来生成sql。请看他的 getBoundSql 方法:

其中 DynamicContext 里面存储着上下文数据。内部类 DynamicContext.ContextMap 存储着已经绑定的sql节点,例如if,forEach啥的。请注意:

 

 那么sqlNode都有神马?有很多,如图

 

 这个命名比较直观,可以看到,这些对应着mapper文件里的节点<if></if>  <trim></trim> <foreach collection=""></foreach>等等,这些类就对应着解析不同的标签。这些类里都有一个关键方法:apply(DynamicContext var1)。他是干啥的呢?他是真正生成sql语句的,不断地递归调用apply方法最后生成sql语句。我们看一个最简单的节点ifSqlNode

 

 再看另一个实现类:TextSqlNode

 类似的类还有一些,可以看到当递归调用到这些类的apply方法的时候,递归就结束了。这是个什么思路呢?请看:

 

所以上图里的生成sql语句的过程就比较清楚了,分别是:

1、进入MixedSqlNode(一般就是rootSqlNode),循环内部的sqlNode;

2、StaticTestNode -> 插入了insert into user(;

3、TrimSqlNode -> 循环递归进入 IfSqlNode对象 -> 根据传入的参数是否满足条件进入 StaticTestSqlNode ->插入了name, 等等;

4、StaticTestNode -> 插入了)values (;

5、TrimSqlNode -> 循环递归进入 IfSqlNode对象 -> 根据传入的参数是否满足条件进入 TestSqlNode ->解析ognl表达式,插入了#{taskCode}代表的1111或2222 等等;

BonedSql

书里面的内容比价全面,这里引用一段《深入浅出mabyties技术原理与实战》内容:

 

4、运行过程 

基本的内容就是我们创建了叫XXXMapper的接口文件,需要mybaties给我们利用动态代理技术生成代理对象,去执行sql语句。MapperProxyFactory 是用于生成代理对象,内容不多。MapperProxy 里面是代理方法的位置,请看invoke 方法:

 再看execute方法:

 

总之最后会进入到sqlSession的select方法:

譬如:(回顾一下mappedStatement !!)

 

 在进入BaseExecutor(抽象类) 瞅一眼query方法:

 

 doQuery方法是一个抽象方法,根据不同的类有不同的实现,可以瞅一眼SimpleExecutor,比较简单

 

SqlSession存在四大对象,可以查资料看一看:

 

 摘一个资料里的图:

 

 

 



这篇关于MyBatis源码阅读的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程