缓存
什么是缓存
存在内存中的临时数据。将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库 数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
前提知道:因为硬盘读写速度远远低于cpu出来速度,cpu需要等硬盘数据读入后才能工作,大量等待时间消耗cpu资源
什么样的数据能使用缓存?
经常查询并且不经常改变的数据。
mybatis缓存
MyBatis提供了一级缓存和二级缓存,其中一级缓存基于SqlSession实现,而二级缓存基于Mapper实现
一级缓存
一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利
原理
当创建一个sqlsession 时候,mybatis会为这个sqlsession对象创建一个新的Executor执行器,而缓存信息就被维护在这Executor执行器中,在Executor 维护两个PerpetualCache属性
localCache属性用于缓存MyBatis查询结果,localOutputParameterCache属性用于缓存存储过程调用结果
MyBatis通过CacheKey对象来描述缓存的Key值。在进行查询操作时,首先创建
CacheKey
对象(CacheKey对象决定了缓存的Key与哪些因素有关系)。如果两次查询操作CacheKey对象相同,就认为这两次查询执行的是相同的SQL语句。CacheKey对象通过BaseExecutor类的createCacheKey()方法创建
查找流程
首先根据缓存
CacheKey从localCache
属性中查找是否有缓存对象,如果查找不到,则调用queryFromDatabase()方法从数据库中获取数据,然后将数据写入localCache对象中。如果localCache中缓存了本次查询的结果,则直接从缓存中获取。
一级缓存声明周期
- 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
- 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
- SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;
- 会话结束
代码分析
二级缓存
MyBatis二级缓存在默认情况下是关闭的,因此需要通过设置cacheEnabled参数值为true来开启二级缓存
<setting name="cacheEnabled" value="true"/>
书上原理
Executor接口有几种不同的实现,分别为SimpleExecutor、BatchExecutor、ReuseExecutor。另外,还有一个比较特殊的CachingExecutor,
CachingExecutor
用到了装饰器模式,在其他几种Executor的基础上增加了二级缓存功能
。CachingExecutor类中维护了一个
TransactionalCacheManager
实例,TransactionalCacheManager类中,通过一个HashMap
对象维护所有二级缓存实例对应的TransactionalCache
对象.
查询的过程:在
CachingExecutor
的query()方法中,首先调用createCacheKey()
方法创建缓存Key对象,然后调用MappedStatement对象的getCache()方法获取MappedStatement对象中维护的二级缓存对象。然后尝试从二级缓存对象中获取结果,如果获取不到,则调用目标Executor对象的query()方法从数据库获取数据,再将数据添加到二级缓存中。当执行更新语句后,同一命名空间下的二级缓存将会被清空
顺序
如果你的MyBatis使用了二级缓存,并且你的Mapper和select语句也配置使用了二级缓存,那么在执行select查询的时候,MyBatis会先从二级缓存中取输入,其次才是一级缓存
自己最后理解
只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据 查出的数据都会被默认先放在一级缓存中
只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中