MyBatis(三)——二级缓存

MyBatis二级缓存

缓存,缓冲存储是MyBatis中用于数据优化提高我们程序执行效率的方式。

  • 一级缓存默认开启,缓存范围SqlSession会话
  • 二级缓存手动开启,属于范围Mapper Namespace

缓存的范围

在这里插入图片描述
MyBatis中这两个命名空间中的所有对象都被存储到JVM的内存中。MyBatis存储对象本质就使用了Map键值对的结构来保存的。

默认情况下SqlSession的缓存也就是一级缓存是开启的,SqlSession中进行的查询结果都会被保存下来,默认的存储周期都是存储在当前的sqlSession中,也就意味着每一个用户所得到的一级缓存可能都是不一样的。当这个会话被释放的时候存储在里面的一级缓存对象都会被清空。 作为SqlSession对象存储一级缓存时间是非常短的,也就意味着存储在这里的一级缓存使用率不高,也可能会浪费额外的存储空间。
为了解决这个问题,MyBatis提供了二级缓存,二级缓存不属于SqlSession,它的作用范围更大,属于整个namespace命名空间,存储在二级缓存对象会被所有的SqlSession共享。

二级缓存运行规则

  • 二级开启后默认所有查询操作均使用缓存
  • 写操作commit提交时对该namespace缓存强制清空
  • 配置useCache=false可以不用缓存
  • 配置flushCache=true代表强制清空缓存

测试一级缓存

@Test
    public void testLv1Cache() throws Exception {
        SqlSession session = null;
        try {
            session = MybatisUtils.openSession();
            RepositoryStock stock = session.selectOne("stock.selectById",20);
            RepositoryStock stock1 = session.selectOne("stock.selectById",20);
            System.out.println(stock.getMaterialName());
            System.out.println(stock.hashCode()+":"+stock1.hashCode());
        }catch (Exception e){
            throw e;
        }finally {
            MybatisUtils.closeSession(session);
        }
    }

调用了两次stock.selectById但是在日志中只打印了一个SQL,虽然得到两个变量但是指向的是相同的内存区域
在这里插入图片描述

中间加commit(),日志中打印出两条sql语句

    @Test
    public void testLv1Cache() throws Exception {
        SqlSession session = null;
        try {
            session = MybatisUtils.openSession();
            RepositoryStock stock = session.selectOne("stock.selectById",20);
            session.commit();
            RepositoryStock stock1 = session.selectOne("stock.selectById",20);
            System.out.println(stock.getMaterialName());
            System.out.println(stock.hashCode()+":"+stock1.hashCode());
        }catch (Exception e){
            throw e;
        }finally {
            MybatisUtils.closeSession(session);
        }
    }

在这里插入图片描述

开启二级缓存

在RepositoryMapper.xml中的< mapper>标签下添加标签

<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>

测试代码

    @Test
    public void testLv2Cache() throws Exception {
        SqlSession session = null;
        try {
            session = MybatisUtils.openSession();
            RepositoryStock stock = session.selectOne("stock.selectById",20);
            System.out.println(stock.getMaterialName());
            System.out.println(stock.hashCode());
        }catch (Exception e){
            throw e;
        }finally {
            MybatisUtils.closeSession(session);
        }
        SqlSession session1 = null;
        try {
            session1 = MybatisUtils.openSession();
            RepositoryStock stock = session1.selectOne("stock.selectById",20);
            System.out.println(stock.getMaterialName());
            System.out.println(stock.hashCode());
        }catch (Exception e){
            throw e;
        }finally {
            MybatisUtils.closeSession(session1);
        }
    }

运行结果只执行了一次SQL,说明配置的二级缓存生效了
Cache Hit Ratio [stock]: 0.5意思是对于[stock]这个对象,缓存的命中率为0.5
在这里插入图片描述

二级缓存配置

cache二级缓存标签的属性

eviction

eviction是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清除

  1. LRU – 最近最久未使用:移除最长时间不被使用的对象。
    O1 O2 O3 O4 … O512
    14 99 83 1 893
  2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  3. SOFT – 软引用:移除基于垃圾收集器状态和软引用规则的对象。
  4. WEAK – 弱引用:更积极的移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval

间隔多长时间自动清理缓存,单位:毫秒
flushInterval=“600000” ,600000毫秒=10分钟
每隔10分钟对缓存进行全局清除,这个时间可以设置时间长一点

size

缓存长度,最多可以缓存多少个对象,如果缓存的是实体类代表缓存一个对象,如果查询结果返回的是一个List集合的话也只会算作是一个对象。
个人建议,在缓存中只需保留单个的实体对象缓存,不要去保留大量的List查询结果这样缓存命中率比较低。相对的如果是selectById根据id号返回唯一的对象,把他保存到缓存中的做法比较好。
size的长度不要太小,比如当前的表有1200多条数据,那么在内存足够的情况下size应该大于1200,意味着所有库存实体对象都会在二级缓存中进行保存。这样做的好处就是,在按id进行查询时会直接从内存中提取,效率是非常非常高的。

readOnly

是否是只读的
设置为true,代表返回只读缓存,每次从缓存取出的是缓存对象本身,这种执行效率较高
设置为false,代表每次取出的是缓存对象的“副本”,每一次取出的对象都是不同的,这种安全性较高

实际开发中大多设置为true就可以了

其他标签中的缓存设置

useCache

是否使用缓存,对于selectAll查询所有的这种形式不推荐把查询结果放入缓存,因为全局查询的时候数据量实在是太大了。
useCache="false"代表查询结果不被放入缓存

<select id="selectAll" resultType="com.zl.mybatis.entity.RepositoryStock" useCache="false">

无论一级缓存二级缓存,当执行了commit()的时候当前的缓存都会被清空。但是在某些特定的需求场景下希望执行完insert语句立马清空缓存,而不是等待commit()执行完再清空。这时候可以使用flushCache=“true”,在SQL执行完以后立即清空缓存

<insert id="insert" parameterType="com.zl.mybatis.entity.RepositoryStock" flushCache="true">

这个配置不只可以放到写数据语句中,也可以放到查询中。执行完这句SQL后缓存就会被清空,清空完缓存这条SQL的执行结果同样不会被放入缓存。

<select id="selectStockMap" resultType="java.util.LinkedHashMap" flushCache="true">
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三毛村滴雪鱼粉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值