zoukankan      html  css  js  c++  java
  • Mybatis缓存

    Mybatis缓存

    Mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能,Mybatis的查询缓存总共有两级,我们称之为一级缓存和二级缓存

    一级缓存

    Mybatis默认开启了一级缓存。任何的insert、update、dalete操作都会清空一级缓存,即MyBatis执行SQL语句之后,这条语句的执行结果被缓存,以后再执行这条语句的时候,会直接从缓存中拿结果,而不是再次执行SQL。但是一旦执行新增或更新或删除操作,缓存就会被清除。
    将mybatis和spring进行整合开发,事务控制在service中。 一个service方法中包括很多mapper方法调用,如果是执行两次service调用查询相同的用户信息,是不走一级缓存的,因为mapper方法结束,sqlSession就关闭,一级缓存就清空。

    接口
    SqlSession: 对外提供了用户和数据库之间交互需要的所有方法,隐藏了底层的细节。默认实现类是DefaultSqlSession
    Executor: SqlSession向用户提供操作数据库的方法,但和数据库操作有关的职责都会委托给Executor 实现类: BaseExecutor ... 。BaseExecutor成员变量之一的PerpetualCache:Cache接口最基本的实现,其实现非常简单,内部持有HashMap,对一级缓存的操作实则是对HashMap的操作
    Cache: MyBatis中的Cache接口,提供了和缓存相关的最基本的操作 实现类:PerpetualCache ....

    1. MyBatis一级缓存的生命周期和SqlSession一致
    2. MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺
    3. MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement

    一级缓存(session级别)场景

    • 同个session进行两次相同查询:只进行1次数据库查询
    • 同个session进行两次不同的查询:进行两次数据库查询
    • 不同session,进行相同查询:进行两次数据库查询
    • 同个session,查询之后更新数据,再次查询相同的语句:更新操作之后缓存会被清除

    二级缓存

    Mybatis默认是没有开启二级缓存

    二级缓存出现的原因

    之所以称之为“二级缓存”,是相对于“一级缓存”而言的。既然有了一级缓存,那么为什么要提供二级缓存呢?在一级缓存中,不同session进行相同SQL查询的时候,是查询两次数据库的。显然这是一种浪费,既然SQL查询相同,就没有必要再次查库了,直接利用缓存数据即可,这种思想就是MyBatis二级缓存的初衷。另外,Spring和MyBatis整合时,每次查询之后都要进行关闭sqlsession,关闭之后数据被清空。所以MyBatis和Spring整合之后,一级缓存是没有意义的。如果开启二级缓存,关闭sqlsession后,会把该sqlsession一级缓存中的数据添加到mapper namespace的二级缓存中。这样,缓存在sqlsession关闭之后依然存在

    二级缓存开启步骤

    1. 在核心配置文件SqlMapConfig.xml中加入:
      <!-- 开启二级缓存总开关 --> <settings> <setting name="cacheEnabled" value="true"/> </settings>

    2. 在UserMapper映射文件中加入:
      <!-- 开启本mapper下的namespace的二级缓存,可以自定义配置 --> <cache/>
      属性:

    • type:cache使用的类型,默认是PerpetualCache
    • eviction: 定义缓存回收的策略:
      • LRU - 最近最少回收,移除最长时间不被使用的对象
      • FIFO - 先进先出,按照缓存进入的顺序来移除它们
      • SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
      • WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
    • flushInterval: 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值
    • size: 最多缓存对象的个数
    • readOnly: 是否只读,若配置可读写,则需要对应的实体类能够序列化 http://www.mybatis.cn/archives/748.html
    • type: 指定自定义缓存的全类名(实现Cache 接口即可)
    • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存
      或在UserMapper映射文件中加入:
      <!--cache-ref代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache--> <cache-ref namespace="mapper.StudentMapper"/>
      或注解方式:
      @CacheNamespace

    二级缓存场景

    对于访问响应速度要求高,但是实时性不高的查询,可以采用二级缓存技术

    二级缓存的使用

    • 在使用二级缓存的时候,要设置一下cache标签中有一个flashInterval属性来定时刷新二级缓存,这个刷新间隔根据具体需求来设置,如:30分钟、60分钟等,单位为毫秒
    • 由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,比如说存储到文件系统中,所以需要给缓存的对象执行序列化。如果该类存在父类,那么父类也要实现序列化
    • 二级缓存是跨SqlSession的,如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询
    • 二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是: 二级缓存 -> 一级缓存 -> 数据库
    • 二级缓存不适应用于映射文件中存在多表查询的情况;通常会为每个单表创建单独的映射文件,由于MyBatis的二级缓存是基于namespace的,多表查询语句所在的namspace无法感应到其他namespace中的语句对多表查询中涉及的表进行的修改,引发脏数据问题。解决的办法:使用Cache ref,让不同的namespace引用其中同一个namespace命名空间,这样两个映射文件对应的SQL操作都使用的是同一块缓存了
    1. MyBatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强
    2. MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻
    3. 在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高

    二级缓存的局限性

    Mybatis二级缓存对细粒度的数据级别的缓存实现不好。场景: 对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次查询都是最新的商品信息,此时如果使用二级缓存,就无法实现。需求:当一个商品信息发生更新只刷新该商品的缓存信息而不刷新其他商品缓存信息;但是因为二级缓存是mapper级别的,当一个商品的信息发生更新,所有的商品信息缓存数据都会清空。解决方法:此类问题,需要在业务层根据需要对数据有针对性的缓存。 比如可以对经常变化的数据操作单独放到另一个namespace的mapper中

  • 相关阅读:
    Lua之math
    Lua之table
    Unity shader学习之轮廓效果
    c#之根据出生日期获得星座信息
    unity之复制文本到剪贴板
    Unity shader学习之屏幕后期处理效果之运动模糊
    Unity之如何从fbx提取Animation clip文件
    c#如何判断字符串是否含中文
    c#之如何转换文本文件编码格式为utf-8
    《Photon》
  • 原文地址:https://www.cnblogs.com/yezhaohui/p/14676625.html
Copyright © 2011-2022 走看看