技术分享

Mybatis缓存

2021-06-22  本文已影响0人  云芈山人

MyBatis提供查询缓存,如果缓存中有数据,则直接从缓存中获取,没有则从数据库查询,用以减轻数据压力,提高系统性能。MyBatis的缓存分为一级缓存和二级缓存,默认情况下一级缓存是开启的,且是不能关闭的。一级缓存是SqlSession级别的,当同一个 SqlSession中进行相同的sql查询时,第二次以后的查询都是从一级缓存中获取,一级缓存最多缓存1024条sql。二级缓存是Mapper级别的,可以跨SqlSession,不同SqlSession可共享。

MyBatis缓存机制

MyBatis缓存机制.png

MyBatis缓存实现原理

Executor接口.png

MyBatis认为的完全相同的查询,只要保证statementId,rowBounds,最后生成的SQL语句,以及这个SQL语句所需要的参数完全一致就可以了。

一级缓存

一级缓存是如何组织的?

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,并为SqlSession对象创建一个Executor执行器,而缓存信息以HashMap的形式维护在这个Executor中,MyBatis将缓存和缓存操作封装在Cache中。


SqlSession对象、Executor对象、Cache对象之间的关系.png

一级缓存原理

第一次发出一个查询sql,sql查询结果写入SqlSession的一级缓存中,缓存使用的数据结构为(HashMap)。
同一个SqlSession发出第二次查询时,就从缓存中获取。如果两次中间出现commit操作(update/insert/delete),则本SqlSession的一级缓存全部清空(为了缓存中记录最新的数据,避免脏读),从数据库查询。

一级缓存的生命周期

  1. 开启数据库会话,创建新的SqlSession对象,SqlSession对象中会有一个Executor对象,Executor对象持有新的PerpetualCache对象;会话结束时,SqlSession对象以及Executor对象和PerpetualCache对象一并销毁。
  2. SqlSession调用close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存不可用。
  3. 如果SqlSession调用clearCache()方法,会清空PerpetualCache对象,但对象仍可用。
  4. SqlSession执行任何一个insert()、update()、delete()操作,会清空PerpetualCache对象,但对象仍可用。

一级缓存的工作流程

  1. 对于某个查询,根据statementId、params、rowBounds来构建key值,根据key值去缓存Cache中查找结果;
  2. 判断从Cache中根据特定的key值取的数据数据是否为空,即是否命中;
  3. 如果命中,则直接返回查询结果;
  4. 如果没有命中:
  1. 结束。

一级缓存性能分析

  1. Session级别的一级缓存设计比较简单,只使用了HashMap来维护,并没有对HashMap的容量和大小进行限制。
  • SqlSession的生存时间很短。使用一个SqlSession对象执行的操作不会太多,执行完就会消亡;
  • 对于某一个SqlSession对象而言,只要执行commit操作(update、insert、delete),都会将这个SqlSession对象中对应的一级缓存清空掉,所以一般情况下不会出现缓存过大,影响JVM内存空间的问题;
  • 可以手动地释放掉SqlSession对象中的缓存。
  1. 一级缓存是粗粒度缓存,没有更新缓存和缓存过期概念。
  • 对于数据变化频率很大,并且需要高时效准确性的数据要求,我们使用SqlSession查询的时候,要控制好SqlSession的生存时间,SqlSession的生存时间越长,它其中缓存的数据有可能就越旧,从而造成和真实数据库的误差;同时对于这种情况,用户也可以手动地适时清空SqlSession中的缓存;
  • 对于只执行、并且频繁执行大范围的select操作的SqlSession对象,SqlSession对象的生存时间不应过长。

二级缓存

二级缓存是mapper级别的,mapper以命名空间为单位创建缓存数据结构(HashMap),二级缓存通过CachingExecutor(Executor的代理对象)实现。

二级缓存原理

所有查询操作,在CachingExecutor都会先匹配缓存中是否存在,否则查询数据库。

二级缓存工作模式

二级缓存机制关键在于Executor对象。若配置【cacheEnable=true】,则为SqlSession创建Executor加上一个装饰者(CachingExecutor)。这时由CachingExecutor对象来完成操作请求。
CachingExecutor对于查询请求,先判断在Application级别的二级缓存是否有结果,如果有直接返回结果。若没有,再交给真正的Executor对象来完成查询,之后CachingExecutor会将真正Executor返回的结果放置在缓存中,在返回给用户。


使用二级缓存工作模式.png

二级缓存划分

MyBatis并不简单将Application就只有一个Cache缓存对象,它将缓存划分的更新,即是mapper级别的(即每一个mapper一个缓存对象)。

1. 为每一个mapper分配一个缓存对象(对于每一个mapper.xml,在其中使用<cache> 节点)。

使用cache节点配置.png

2. 多个mapper共用一个缓存对象(使用<cache-ref namespace="">节点,来指定你的这个Mapper使用到了哪一个Mapper的Cache缓存)。

cache-ref共用缓存.png

二级缓存的开启

MyBatis对二级缓存的支持粒度较细,需要具体指定到某条查询语句上。如果要开启二级缓存,需做到如下三点:

  1. MyBatis支持二级缓存的总开关:全局配置变量参数【cacheEnabled=true】。
  2. 该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效。
  3. 该select语句的参数 useCache=true。

二级缓存的实现

MyBatis 对于二级缓存的实现非常灵活,自己内部实现了Cache的一系列的实现类,并提供了各种缓存刷新策略LRU、FIFO等。同时它也允许自定义Cache接口实现,需实现org.apache.ibatis.cache.Cache接口,然后将Cache的实现类配置在<cache type="">节点的type属性上。此外,它也支持与第三方缓存库如Memecached的集成。

二级缓存的实现有三种选择:

  1. MyBatis自身提供的缓存实现;

    • MyBatis定义了大量的Cache的装饰器来增强Cache缓存的功能


      Cache装饰器.png
    • 对于每个Cache而言,都有容量限制,MyBatis提供了各种策略来对Cache缓存的容量进行控制,以及对于Cache中的数据进行刷新和置换。主要有以下几个刷新和置换策略:

      LRU:Least Recently Used,最近最少使用算法,即缓存中容量满了,会将缓存最近最少使用的数据清楚,添加上新的记录。

      FIFO:First In First Out,先进先出算法,即缓存中容量满了,会将最先进来的数据清楚。

      Scheduled:指定时间间隔清空算法,该算法会以指定的某一个时间间隔将Cache缓存中的数据清空。

  2. 用户自定义的Cache接口实现;

  3. 跟第三方内存缓存库的集成;

二级缓存应用场景

二级缓存局限性

Mybatis二级缓存对细粒度的数据级别的缓存实现不好。

上一篇 下一篇

猜你喜欢

热点阅读