缓存

mybatis提供一级缓存和二级缓存

  • mybatis一级缓存是一个SqlSession级别,sqlsession只能访问自己的一级缓存的数据

  • 二级缓存是跨sqlSession,是mapper级别的缓存,对于mapper级别的缓存不同的sqlsession是可以共享的。

一级缓存

第一次发出一个查询sql,sql查询结果写入sqlsession的一级缓存中,缓存使用的数据结构是一个map

  • key:hashcode+sql+sql输入参数+输出参数(sql的唯一标识)

  • value:用户信息

  • 第一次查询,把查询结果存到一个map中;第二次以相同sql查询,直接从缓存(map)中获取结果,即两次查询结果都是同一个Java对象,内存地址相同

同一个sqlsession再次发出相同的sql,就从缓存中取不走数据库。如果两次中间出现commit操作(修改、添加、删除)或清除缓存(sqlSession.clearCache()),本sqlsession中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。

Mybatis一级缓存值得注意的地方:

  • Mybatis默认就是支持一级缓存的,并不需要我们配置.

  • mybatis和spring整合后进行mapper代理开发,不支持一级缓存,mybatis和spring整合,spring按照mapper的模板去生成mapper代理对象,模板中在最后统一关闭sqlsession

一级缓存创建:在执行SQL语句时

一级缓存保存:sqlSession.commit()sqlSession.close()

一级缓存清除:sqlSession.clearCache(),增、删、改操作

二级缓存

二级缓存的范围是mapper级别(mapper同一个命名空间,多个sqlSession可以共享缓存),mapper以命名空间为单位创建缓存数据结构,结构是map。

img

二级缓存配置

  • 1、mybatis配置文件配置

需要我们在Mybatis的配置文件中配置二级缓存

    <!-- 全局配置参数 -->
    <settings>
        <!-- 开启二级缓存 -->
        <setting city="cacheEnabled" value="true"/>
    </settings>
  • 2、映射文件Mapper.xml配置

二级缓存的范围是mapper级别的,因此我们的Mapper如果要使用二级缓存,还需要在对应的映射文件中配置..

    <cache/>

cache 标签属性

  • eviction : 缓存回收策略,有这几种回收策略(默认是 LRU 最近最少回收策略)

    • LRU - 最近最少回收,移除最长时间不被使用的对象

    • FIFO - 先进先出,按照缓存进入的顺序来移除它们

    • SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象

    • WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象

  • flushinterval 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值

  • readOnly: 是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修改

  • size : 缓存存放多少个元素

  • type: 指定自定义缓存的全类名(实现Cache 接口即可)

  • blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。

  • 3、POJO序列化

mybatis二级缓存需要将查询结果映射的pojo实现 java.io.serializable接口,如果不实现则抛出异常:

org.apache.ibatis.cache.CacheException: Error serializing object.  Cause: java.io.NotSerializableException: cn.itcast.mybatis.po.User

二级缓存可以将内存的数据写到磁盘,存在对象的序列化和反序列化,所以要实现java.io.serializable接口。 如果结果映射的pojo中还包括了pojo,都要实现java.io.serializable接口。

二级缓存失效

  • 第一次sqlSession未提交,SQL 语句产生的查询结果还没有放入二级缓存

  • 增、删、改 操作

二级缓存源码

  • 二级缓存创建

    • 二级缓存的创建是使用 Resource 读取 mybatis的XML 配置文件开始的,读取配置文件后,需要对XML创建 Configuration并初始化

    • 根据配置文件中的<mapper>标签,去找对应的映射文件(namespace)

    • 找映射文件中的<cache>等与二级缓存相关的标签(看这个namespace是否开启二级缓存),再找sql语句标签

二级缓存注意事项

  1. 缓存是以namespace为单位的,不同namespace下的操作互不影响。

  2. insert,update,delete操作会清空所在namespace下的全部缓存。

  3. 通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace

  4. 多表操作一定不要使用二级缓存,因为多表操作进行更新操作,一定会产生脏数据

如果不能使用多表操作,二级缓存不就可以用一级缓存来替换掉吗?而且二级缓存是表级缓存,开销大,没有一级缓存直接使用 HashMap 来存储的效率更高,所以二级缓存并不推荐使用

禁用二级缓存

对于变化频率较高的sql,需要禁用二级缓存:

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

对查询频率高,变化频率低的数据建议使用二级缓存。

对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度

业务场景比如:

  • 耗时较高的统计分析sql、

  • 电话账单查询sql等。

实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

 

原文地址:https://www.cnblogs.com/yjh1995/p/13893766.html