mybatis一级缓存原理
mybatis篇
一级缓存也叫做本地缓存,mybatis中一级缓存是默认开启的,作用域是sqlsession级别的,如下图,同一个sqlsession下执行2次相同的查询,sql只会执行第一次,第二次直接从缓存中获取。
image image继续开启一个新的sqlsession执行同样的查询,发现sql语句执行了。
image image可以看到一级缓存的范围就是sqlsession级别的,接下来我们来看一下源码就知道这是如何设计的。
首先看下SqlsessionFactory的创建
从这里可以看到,SqlsessionFactory的创建返回的是一个DefaultSqlsessionFactory对象,并且将我们的mybatis-config.xml文件解析成Configuration对象保存在内部。
image image其中主要看下
mapperElement(root.evalNode("mappers"));
image
image
image
这里比较关键,往knownMappers的Map中存放了key为Class对象,Value为MapperProxyFactory的对象,因为后面getMapper获得接口的时候实际上就是从这里面拿到值然后生成一个代理对象的
image image从这里可以看到我们之前如果配置是package扫描mapper接口的话,他会将
加载resource下接口全限定名的xml文件。
parseStatement:
image image image而parseStatement的作用就是将xml中的所有标签解析成MapperStatement对象并保存在Configuration中,到这里,我们就大致知道SqlsessionFactory的初始化过程了。接下来我们就揭开为什么我们的接口没有实现类,但他却能工作。
image image image image缓存似乎慢慢浮出水面了,然而这里的cacheEnable是控制二级缓存的,先忽略,在这里我们知道了opensession返回的是一个里面Executor为SimpleExecutor的DefaultSqlsession的对象
MybatisUserinfoMapper userinfoMapper = sqlSession.getMapper(MybatisUserinfoMapper.class);
最为重要的是MybatisUserinfoMapper这个对象究竟是个什么东西,传入的是MybatisUserinfoMapper最后得到的也是自己。
image image可以看到,这里传入的type正好是之前扫描mapper的时候存入的MapperProxyFactory的对象。
image image image真相浮出水面,这不就是jdk动态代理,可见MybatisUserinfoMapper的真正面目是MapperProxy,而动态代理执行方法时最终执行的是invoker方法。
image image这里我们看select方法
image image image这里拿着对象全限定名+方法名找到了对应xml配置的sql
image image其中有一个ms.isFlushCacheRequired的方法,如果满足则会把一级缓存清除。其中配置flushCache为true就是每次会清空一级缓存,默认不配置的话select标签是false,其他的是true,这里把selectByKey设置为true,执行刚刚的语句,发现执行了3次,都没走缓存了。
image image image最后没走缓存就查询数据库了
image最终执行的就是jdbc的查询。至此,这就是我们接口的真面目
总结:mybatis运行如下几个步骤
- 创建SqlSessionFactory,其中Mapper文件的扫描。
- 创建Sqlsession对象,返回的是一个带有SimpleExecutor对象的DefaultSqlsessionFactory
- 获取Mapper对象,传入Class对象,获取MapperProxyFactory生成的MapperProxy代理对象,执行改对象的方法就是执行MapperProxy的invoker方法,根据Class.getName+method.getName找到具体的MappedStatement语句,先查询缓存中是否有值,如果有则返回缓存中的值,没有则走jdbc相关的逻辑执行sql语句,最后返回具体的值并放入缓存。