Mybatis中的⼀⼆级缓存通俗易懂解析
前端用什么框架oracle设置唯一键前⾔:
缓存我们都知道,是把数据存放在内存中,依靠内存的⾼速读写能⼒提⾼查询效率,那么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是相互获取不到对⽅的缓存的。
ajax代码片段根据下图,⽤户查询SQL进来后,查询缓存看有没有,没有再读取,然后写⼊缓存,然后返回。mysql语句的执行顺序
⼀级缓存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最近最少使⽤淘汰算法:
异步通信的通信双方没有公共的时钟标准(7)怎么配置
这个问题暂时不在这⾥展开,关于这些配置项,⽹上教程⼀个⽐⼀个详细,⽆⾮就是改哪个配置⽂件,enable=true,选择⼀些参数,缓存个数,过期时间之类的使⽤细节配置…配置好之后验证,都是⽐较轻松简单的。所以尽情百度吧。
现总结到这⾥,后续会持续补充,有说错的欢迎⼤佬修正哈~
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论