Mybatis中的一二级缓存通俗易懂解析

前言:
缓存我们都知道,是把数据存放在内存中,依靠内存的高速读写能力提高查询效率,那么mybatis中的一二级缓存又是什么呢?有什么区别呢?

我们一上来先不说概念,以更简单理解的角度入手

(1)实际业务需求

假设有个业务需求,需要读取Hbase中二进制格式的数据,要我们设计一个类似ORM(Object Relational Mapping 对象关系映射)映射的功能,我们会怎么做?这一块我在自定义注解中读取Hbase列族列名解析后映射到对应的对象中做过,只需要遵循一定规范,常见例如驼峰,例如蛇形,甚至自己定义的其它规则,就能实现从列,映射到对象中的属性,用户查询的时候返回解析后的对象即可,如下图,其中SQL执行器就是帮我们校验SQL语法错误,并且获取连接池中的连接,然后执行SQL,并且返回结果的。(假设下面的狗头都是同一个用户在同一次请求中发起的同一种查询)

在这里插入图片描述
但是,需要每次请求都解析一次吗?无疑是非常浪费资源的,我们就可以想象:
我们可以把查询过的数据缓存起来,当用户发起的查询条件和查询语句一致的时候,我们就可以直接返回对应的结果,不需要再走Hbase获取和解析,而通过查询条件和语句key,找到对应的value。这不就是map结构吗?而这也就是一级缓存的概念。

(2)一级缓存

Mybatis中也是采用了Map这种键值对形式,把用户的查询条件和查询语句做为Key,把上一次查询读取磁盘文件的结果放在Value中。提高了查询效率。
一级缓存是通过SqlSession对象来做的,这个对象也是别人设计的,主要作用就是执行SQL语句拿到Result,这个对象本身会自带一个缓存用的map,所有在该Session内的查询,如果是同一句SQL同样参数,那么就直接获取map中缓存的数据返回。所以它的作用域很小,仅限于当前的Session,其它的Session是相互获取不到对方的缓存的。
根据下图,用户查询SQL进来后,查询缓存看有没有,没有再读取,然后写入缓存,然后返回。
在这里插入图片描述
一级缓存Mybatis是默认开启的,具体验证很简单,随便写一个查询语句,同一个session中做两次查询,能看到语句只执行了一次并且返回的两个结果集内存地址是完全相同的,也就是同一个。
一级缓存的生命周期很明显,与SqlSession共存亡!

(3)二级缓存

上面一级缓存概念如果看明白是干嘛的了,我们就接着看它有啥局限性,很明显,它不能跨越多个SqlSession,也就是只有在一次会话中的多次查询可以读取到SqlSession本地缓存,而一个Session往往属于一个用户端请求,多个Session之间的数据可能存在不一致问题
在这里插入图片描述
为了解决这种又浪费性能,于是出现了二级缓存。那么该怎么定义二级缓存的范围呢?全部Session都共享吗?不太现实,我们仔细想想,是不是大部分某个业务相关的查询请求,我们都会放在同一个Mapper里面?mapper里面是不是有配置一个全局唯一的NameSpace?这个NameSpace,直接翻译叫命名空间,不要死背了,它就是一个分组,一个做为二级缓存简单的逻辑分组。所以有句八股文就叫做:“二级缓存的范围是NameSpace(Mapper)级别的”,一个Mapper对应一个NameSpace,其实都是一个道理。
在这里插入图片描述
上图就是他们的执行顺序和关系,注意name space缓存是共享的,session缓存是独享的。而所谓的二级缓存,它的数据结构也是map,也是把查询参数+SQL语句做为Key,查询结果做为Value
二级缓存的生命周期就比较长了,因为共享,一直保存在缓存执行器中,所以跟redis这种常驻内存的缓存一样需要内存淘汰策略(下面会介绍几种常见的)

(4)三级四级缓存有吗?

其实不要管什么分级,从自己思考的角度出发,我不但想跨Name Space,我更加想跨应用,跨服务,也就是ABC服务都能先从自定义缓存中获取数据,没有再走Mybatis代码查什么二级一级再到查库表,是不是很熟悉,这不就是MemberCahce和Redis的常用方法吗?又或者我觉得Mybatis提供的都是Key – Value性的Map结构缓存,不太符合业务需求,那么也可以自己DIY呀。
在代码中,我们也可以整一套服务,专门负责缓存数据的,或者实现Mybatis提供给我们的Cache接口,或者整合上面说的Redis这些第三方的(mybatis整合redis做自定义缓存非常容易,加个cache type参数配置就可以,网上一大堆),都能实现N层不同维度不同粗细粒度的缓存结构呀,所以,死背多少级的八股没意义呀,搞懂它到底想表达什么,效果会不会更好呢?

(5)缓存失效

1:缓存保存在HashMap,那么当发生insert,delete,update之类的写请求,就会调用到一个cache.clear();方法,这个方法会把对应的map做一次map.clear(); 也就是把缓存给清空。
2:当我们配置的内存回收策略/缓存过期策略的时机到了,缓存也会失效。一般是二级缓存才手动配置,一级缓存它的生命周期较短,而且默认开启,一般不需要额外配置什么。二级缓存在启动的时候就会读取mybatis-conf配置文件信息,首先了解用户需不需要开启,再了解用户想要怎么开启,根据里面配置的标签值拿到对应的参数。这一项就没啥好说的了,大家设计都会这样设计。
3:服务重启,这个就没必要说了,它也没像redis一样提供RDB/AOF之类的持久化机制,所以当服务重启,百分百全部查询走数据库,这也是为什么引入第三方缓存服务很重要的原因。

(6)内存回收策略/缓存过期策略

1:FIFO 先进先出:按对象进入缓存的顺序移除他们,简单说就是移除最老的那一个缓存对象。
2:SOFT 软引用 / WEAK 弱引用:通过Java中的强弱软虚等不同的对象创建方式来配合
JVM GC回收缓存内存
3:Schedule:定时清除缓存数据
4:(这个好像是默认的也是最高效的)LRU最近最少使用淘汰算法:LRU算法Java实践

(7)怎么配置

这个问题暂时不在这里展开,关于这些配置项,网上教程一个比一个详细,无非就是改哪个配置文件,enable=true,选择一些参数,缓存个数,过期时间之类的使用细节配置…配置好之后验证,都是比较轻松简单的。所以尽情百度吧。

😃😃😃😃😃😃😃😃😃😃😃😃😃😃😃现总结到这里,后续会持续补充,有说错的欢迎大佬修正哈~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值