美文网首页
MyBatis(五)缓存

MyBatis(五)缓存

作者: guideEmotion | 来源:发表于2019-07-07 18:58 被阅读0次

    一 缓存机制

    MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置定制。缓存可以极大的提升查询效率
    MyBatis系统中默认定义了两级缓存。一级缓存和二级缓存
    – 1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
    – 2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    – 3、为了提高扩展性。 MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

    架构图

    image.png

    二 一级缓存

    一级缓存是sqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap),用于存储缓存数据。不同的sqlSession之间的缓存区域(HashMap)是互不影响的。

    一级缓存(local cache), 即本地缓存, 作用域默认为sqlSession。当 Session flushclose 后, 该Session 中的所有 Cache 将被清空
    • 本地缓存不能被关闭, 但可以调用clearCache()来清空本地缓存, 或者改变缓存的作用域.
    • 在mybatis3.1之后, 可以配置本地缓存的作用域.
    在 mybatis.xml 中配置

    两种级别

    Mybatis提供了一级缓存的方案来优化在数据库会话间重复查询的问题。实现的方式是每一个SqlSession中都持有了自己的缓存,一种是SESSION级别,即在一个Mybatis会话中执行的所有语句,都会共享这一个缓存。一种是STATEMENT级别,可以理解为缓存只对当前执行的这一个statement有效。Statement,即不使用一级缓存

    工作流程

    根据一级缓存的工作流程,我们绘制出一级缓存执行的时序图,如下图所示。



    主要步骤如下:

    1. 对于某个Select Statement,根据该Statement生成key
    2. 判断在Local Cache中,该key是否用对应的数据存在。
    3. 如果命中,则跳过查询数据库,继续往下走。
    4. 如果没命中:
      4.1 去数据库中查询数据,得到查询结果;
      4.2 将key和查询到的结果作为key和value,放入Local Cache中。
      4.3. 将查询结果返回;
    5. 判断缓存级别是否为STATEMENT`级别,如果是的话,清空本地缓存。

    工作场景

    image.png
    (1). 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
    (2). 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。(3). 第二次发起查询用户id为1的用户信息,先去找缓存`中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。mybatis默认支持一级缓存的。测试很简单,这里就不贴代码了。

    三 二级缓存

    • 二级缓存(second level cache),全局作用域缓存
    • 二级缓存默认不开启,需要手动配置
    • MyBatis提供二级缓存的接口以及实现,缓存实现要求;POJO实现Serializable接口
    二级缓存在 SqlSession 关闭或提交之后才会生效

    使用步骤

    – 1、全局配置文件中开启二级缓存
    <setting name="cacheEnabled" value="true"/>
    – 2、需要使用二级缓存的映射文件处使用cache配置缓存cache-ref:cache-ref代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache
    • <cache />
    – 3、注意:POJO需要实现Serializable接口

    映射文件的缓存配置

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
    
    <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> -->
    
    <cache-ref namespace="mapper.StudentMapper"/>
    

    属性

    • eviction:缓存的回收策略:
      LRU – 最近最少使用的:移除最长时间不被使用的对象。
      • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
      • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
      • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
      • 默认的是LRU
    • flushInterval:缓存刷新间隔
      缓存多长时间清空一次,默认不清空,设置一个毫秒值
    • readOnly:是否只读:
      true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
      mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
      false:非只读:mybatis觉得获取的数据可能会被修改。
      mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢
    • size:缓存存放多少元素;
    • type:指定自定义缓存的全类名;实现Cache接口即可;
    • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存

    流程

    当开启二级缓存后,会使用CachingExecutor装饰Executor,在进入后续执行前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示。

    image.png
    在二级缓存的使用中,一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存是被多个SqlSession共享着的,是一个全局的变量
    当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库

    不同namespace查出的数据会放在自己对应的缓存中(map)
    效果:数据会从二级缓存中获取

    • 查出的数据都会被默认先放在一级缓存中。
    • 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中

    和缓存有关的设置/属性

    • 每个select标签都有useCache="true":false:不使用缓存(一级缓存依然使用,二级缓存不使用)
    • 每个增删改标签的:flushCache="true":(一级二级都会清除):
      增删改执行完成后就会清除缓存
      测试:flushCache="true":一级缓存就清空了;二级会被清除;
      查询标签:flushCache="false":
      如果flushCache=true;每次查询之后都会清空缓存;缓存是没有被使用的

    参考

    1. Mybatis学习总结(九)——查询缓存
    2. https://www.jianshu.com/p/c553169c5921

    相关文章

      网友评论

          本文标题:MyBatis(五)缓存

          本文链接:https://www.haomeiwen.com/subject/ljkihctx.html