在mybatis当中实际上只有两种方法的执行,一是query二是update。所有的查询方法到最后都会取调用query,其它三种方法最后都会取调用update。之间提过mybatis实际上是jdbcTmeplate的封装,这里就体现出来了,那么接下来就开始学习吧。
一.方法的执行流程
先上两张图
可以看出两种方法都是通过执行器执行,通过sqlSession执行的各类selectXXX和增删改操作在做了动态sql和参数相关的封装处理后,都会交给对应的执行器去处理,包括一、二级缓存的管理,事务的具体管理,Statement和具体JDBC层面优化的实现等等,通过策略者模式来使用这些执行器。
那么执行器有那些类型呢?
上图就是执行器的大概架构,值得注意的是下面三个执行器默认使用的是SimpleExecutor。这些执行器也都可以自己配置的,我没有仔细研究过,有兴趣可以自己研究一下。大概描述了这些东西后,开始方法的执行吧!
1.query方法的执行
在执行具体方法前先把二级缓存打开,二级缓存是需要配置打开的,如果不使用二级缓存可以不打开,但也是这个流程
首先在配置文件mybatis-config.xml当中编写
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
然后再对应的配置文件当中填写
<cache type="org.apache.ibatis.cache.impl.PerpetualCache"></cache>
type可以不配置,有默认配置的。
二级缓存在每个标签都有对应的控制,有是否打开二级缓存userCache和是否刷新二级缓存flushCache 两种配置。
userCache是用来设置是否禁用二级缓存的,useCache查询方法query默认为true,其他三种使用update的默认是false,在statement中设置useCache=false可以禁用当前select语句的二级缓存。
flushCache 属性,select方法默认情况下为false,其他三种方法默认是打开的。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
讲明白这些后我们开始执行方法
从上图可以看到query方法首先是取出sql和创建了一个key,key一般是map当中才会用到难道下面会使用到map吗?接着往下面看
首先查看刷新缓存,查看一下是否和上面判断一样select默认关闭!
果然一致。
接下来看二级缓存开启后是否默认打开
确实是默认打开的,上面图片可以发现key确实是用来取数据了,
怎么取的呢?
最终发现是通过二级缓存实际上是通过map来储存数据的,key值为statementId+offset+limit+sql+paramValueList+environmentId这些组成,value就是取出的数据,如果从map当中取到数据就直接返回了。我们是没有取到,继续执行到BaseExecutor
可以看到这里还有是先去一个map里面取数据,没有取到才会真正去数据库里面查询,这个map就是一级缓存,一级缓存是默认打开的,当数据库查询完毕后,会清空一级缓存,然后会在这里保存一份最新数据
这里证明了确实是储存一份在一级缓存,最后调用默认的执行器SimpleExecutor来取数据库当中数据
里面就是只有jdbc来取数据的,到这里就基本上结束了,当然其中肯定还有一些处理结果集的操作,自己有兴趣自己看吧,没什么特殊的,还记得之前储存的别名映射数据吗,正好接下来使用到了这些数据,最后上一张图总结一下
2.update方法的执行
和上面实际上是一个流程,但是不同的是query方法是要储存数据到一二级缓存,update是要清空一二级缓存
先去CachingExecutor清空二级缓存
update方法的flushCache是默认打开的,是因为增删改操作比较危险,可能存在脏读,所以默认需要刷新
但是userCache是默认关闭的,方法处理的时候根本不会去走二级缓存
然后去BaseExecutor清空一级缓存
最后去SimpleExecutor执行sql
这样就结束了
二. 一二级缓存探讨
1.一级缓存是sqlsession会话级别的,如果不是一个会话执行的sql,那么存储在不同的位置,当前sqlsession接收了一级缓存也释放了。
2.二级缓存是mapper级别的·,缓存的数据是不会受到sqlsession影响的,只会受到sql的参数影响。
3.一二级缓存的key值都是一样组成的statementId+offset+limit+sql+paramValueList+environmentId,一二级缓存如果都打开,查询结果会在两个缓存都存储,但是由于程序执行的顺序,实际上一级缓存是不会得到使用的。
4.一二级缓存的刷新是不会互相影响的,因为是不同的map存储的
5.二级缓存存储的数据如果太多的话,是有一些淘汰的算法的,默认是LRU淘汰算法,即删除使用最少的。
6.一二级缓存的刷新实际上是清空所有的数据,也就是说刷新就是清空