Mybatis源码(九)— chche
Mybatis中共有三级缓存,其中一级缓存默认开启,作用范围是在sqlSession对象(同一个会话),二级缓存需要手动配置开启,作用范围是在sqlSessionFactory对象下的同一个namespace范围(所以二级缓存是可以多个会话共享的,不过如果多表关联查询,会失效)。三级缓存不用太关注。
二级缓存配置
- mybatis-config.xml全局配置,不配置也可以,默认true。
<setting name="cacheEnabled" value="true"/>
- 在对应的mapper.xml中对< cache>标签进行配置
<!-- eviction:缓存的清除策略,当缓存达到上限后会自动触发对应算法清除缓存 flushInterval:清除缓存的时间间隔,在指定时间会自动清理缓存,单位为毫秒 size:缓存存储大小,指定保存对象的个数(List集合也算一个对象),一般不推荐将List集合放入缓存中,因为List集合较为多变,命中率较 readOnly:是否为只读,设置为true代表数据缓存只读,每次从缓存取出的对象是对象本身,执行效率较高;设置为false代表读取的对象为缓存的副本,每次取出的对象是不同的,这种操作对数据较为安全 --> <cache eviction="LRU" flushInterval="60000" size="1000"/> <!-- 还可以在select、update等标签中,指定是否将结果放入缓存或执行后是否直接清除缓存--> <!-- 使用useCashe将结果集放入缓存中 --> <select id="xxx" resultType="xxx" useCache="true">SELECT * FROM xx </select> <!-- 针对于某些情景下,想要在插入完成后就清空缓存可以使用flushCache属性,设置为true则会在SQL执行结束后立刻清空缓存 --> <update id="update" parameterType="com.mybatis.entity.Good" flushCache="true">UPDATE xx SET aa = #{aa}WHERE bb = #{bb} </update>
Cache
Cache
cache包下的Cache接口约定了整个缓存的规范,有不同的Cache的实现类来实现它完成不同的功能。看类中方法可发现,其实就是相当于对一个map的存取。
package org.apache.ibatis.cache;import java.util.concurrent.locks.ReadWriteLock;/*** 缓存*/
public interface Cache {/*** 该缓存对象的id*/String getId();/*** 向缓存中添加数据,key是CacheKey,value是查询结果*/void putObject(Object key, Object value);/*** 根据指定的key,在缓存中查找对应的结果对象**/Object getObject(Object key);/*** 删除key对应的缓存项**/Object removeObject(Object key);/*** 清空缓存*/void clear();/*** 缓存项的个数**/int getSize();/*** 获取读写锁*/default ReadWriteLock getReadWriteLock() {return null;}
}
在调用Configuration的无参构造时,同样会对常见的Cache对象的Alias(别名)做映射处理。
public Configuration() {typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);typeAliasRegistry.registerAlias("FIFO", FifoCache.class);typeAliasRegistry.registerAlias("LRU", LruCache.class);typeAliasRegistry.registerAlias("SOFT", SoftCache.class);typeAliasRegistry.registerAlias("WEAK", WeakCache.class);}
接下来就根据Configuration映射的顺序,来逐一查看对应的缓存类。
PerpetualCache
PerpetualCache类代表永久缓存,用HashMap来实现对缓存的存储。
/**** 永久缓存* 一旦存入就一直保持** @author Clinton Begin*/
public class PerpetualCache implements Cache {// Cache对象的唯一标识private final String id;// 记录缓存想的map对象private final Map<Object, Object> cache = new HashMap<>();public PerpetualCache(String id) {this.id = id;}@Overridepublic String getId() {return id;}@Overridepublic int getSize() {return cache.size();}@Overridepublic void putObject(Object key, Object value) {cache.put(key, value);}@Overridepublic Object getObject(Object key) {return cache.get(key);}@Overridepublic Object removeObject(Object key) {return cache.remove(key);}@Overridepublic void clear() {cache.clear();}@Overridepublic boolean equals(Object o) {// 只要id相等就认为两个cache相同if (getId() == null) {throw new CacheException("Cache instances require an ID.");}if (this == o) {return true;}if (!(o instanceof Cache)) {return false;}Cache otherCache = (Cache) o;return getId().equals(otherCache.getId());}@Overridepublic int hashCode() {if (getId() == null) {throw new CacheException("Cache instances require an ID.");}return getId().hashCode();}
}
除了上面的PerpetualCache,其余四个类都在org.apache.ibatis.cache.decorators包下,使用到了装饰者模式。
FifoCache
底层为了了一个LinkedList链表来记录了cache的先后顺序(每次从后添加,如果size > 1024,则从头先remove ),默认LinkedList大小为1024。除此之外,还是使用装饰者模式,调用其他的Cache对象来完成Cache的存储。
/*** FIFO缓存* 这个类就是维护一个FIFO链表,其他都委托给所包装的cache去做。典型的装饰模式** FIFO (first in, first out) cache decorator.**/
public class FifoCache implements Cache {// 底层被装饰的底层Cache对象private final Cache delegate;// 用于记录key进入缓存的先后顺序private final Deque<Object> keyList;// 记录了缓存项的上限,超过该值,则需要清理最老的缓存项private int size;public FifoCache(Cache delegate) {this.delegate = delegate;this.keyList = new LinkedList<>();this.size = 1024;}@Overridepublic String getId() {return delegate.getId();}@Overridepublic int getSize() {return delegate.getSize();}public void setSize(int size) {this.size = size;}@Overridepublic void putObject(Object key, Object value) {// 检测并清理缓存cycleKeyList(key);// 添加缓存项delegate.putObject(key, value);}@Overridepublic Object getObject(Object key) {return delegate.getObject(key);}@Overridepublic Object removeObject(Object key) {return delegate.removeObject(key);}@Overridepublic void clear() {delegate.clear();keyList.clear();}private void cycleKeyList(Object key) {// 记录keykeyList.addLast(key);// 如果缓存达到上限,则清理最老的缓存项if (keyList.size() > size) {Object oldestKey = keyList.removeFirst();delegate.removeObject(oldestKey);}}
}
LruCache
和FifoCache的区别在于,它使用了LinkedHashMap来记录着Cache的顺序,在进行过期策略时,删除最少使用的Cache。
/*** 最近最少使用缓存* 基于 LinkedHashMap 覆盖其 removeEldestEntry 方法实现。** Lru (least recently used) cache decorator.** @author Clinton Begin*/
public class LruCache implements Cache {// 被装饰的底层cache对象private final Cache delegate;// 有序的hashmap,用于记录key最近的使用情况private Map<Object, Object> keyMap;// 记录最少被使用的缓存项的keyprivate Object eldestKey;public LruCache(Cache delegate) {this.delegate = delegate;setSize(1024);}@Overridepublic String getId() {return delegate.getId();}@Overridepublic int getSize() {return delegate.getSize();}public void setSize(final int size) {// 重新设置缓存大小时,会重置keyMap字段,注意LinkedHashMap构造函数的第三个参数,true表示该LinkedHashMap记录的顺序是access-orderkeyMap = new LinkedHashMap<Object, Object>(size, .75F, true) {private static final long serialVersionUID = 4267176411845948333L;// 当调用LinkedHashMap.put方法,会调用此方法@Overrideprotected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {boolean tooBig = size() > size;// 如果已达到缓存上线,则更新eldestKey字段,后面会删除该项if (tooBig) {// 把eldestKey存入实例变量eldestKey = eldest.getKey();}return tooBig;}};}@Overridepublic void putObject(Object key, Object value) {// 添加缓存项delegate.putObject(key, value);// 删除最久未使用的缓存项cycleKeyList(key);}@Overridepublic Object getObject(Object key) {// 修改LinkedHashMap中记录的顺序keyMap.get(key); // touchreturn delegate.getObject(key);}@Overridepublic Object removeObject(Object key) {return delegate.removeObject(key);}@Overridepublic void clear() {delegate.clear();keyMap.clear();}private void cycleKeyList(Object key) {keyMap.put(key, key);// eldestKey不为空,表示已经达到缓存上限if (eldestKey != null) {// 删除最久未使用的缓存项delegate.removeObject(eldestKey);eldestKey = null;}}
}
SoftCache
JVM中对象的引用关系分为强、软、弱、虚。每种引用关系在JVM进行垃圾回收时回收的标准是不同的,Mybatis的SoftCache其本质就是软引用。
public class SoftCache implements Cache {// 在SoftCache中,最近使用的一部分缓存项不会被GC回收,这就是通过将其value添加到hardLinksToAvoidGarbageCollection集合中实现的private final Deque<Object> hardLinksToAvoidGarbageCollection;// 引用队列,用于记录已经被GC回收的缓存项对应的SoftEntry对象private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;// 底层被装饰的底层Cache对象private final Cache delegate;// 强连接的个数,默认是256private int numberOfHardLinks;public SoftCache(Cache delegate) {this.delegate = delegate;//默认链表可以存256元素this.numberOfHardLinks = 256;this.hardLinksToAvoidGarbageCollection = new LinkedList<>();this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();}@Overridepublic String getId() {return delegate.getId();}@Overridepublic int getSize() {removeGarbageCollectedItems();return delegate.getSize();}public void setSize(int size) {this.numberOfHardLinks = size;}@Overridepublic void putObject(Object key, Object value) {// 清除已经被GC回收的缓存项removeGarbageCollectedItems();// 向缓存中添加缓存项delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries));}@Overridepublic Object getObject(Object key) {Object result = null;@SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache// 从缓存中查找对应的缓存项SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key);// 检测缓存中是否有对应的缓存项if (softReference != null) {// 获取SoftReference引用的valueresult = softReference.get();// 已经被GC回收if (result == null) {// 从缓存中清除对应的缓存项delegate.removeObject(key);// 未被GC回收} else {// See #586 (and #335) modifications need more than a read locksynchronized (hardLinksToAvoidGarbageCollection) {// 缓存项的value添加到hardLinksToAvoidGarbageCollection集合中保存hardLinksToAvoidGarbageCollection.addFirst(result);if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {// 超过numberOfHardLinks,将最老的缓存项从hardLinksToAvoidGarbageCollection集合中清除hardLinksToAvoidGarbageCollection.removeLast();}}}}return result;}@Overridepublic Object removeObject(Object key) {removeGarbageCollectedItems();return delegate.removeObject(key);}@Overridepublic void clear() {synchronized (hardLinksToAvoidGarbageCollection) {// 清理强引用集合hardLinksToAvoidGarbageCollection.clear();}// 清理被GC回收的缓存项removeGarbageCollectedItems();// 清除底层delegate缓存中的缓存项delegate.clear();}private void removeGarbageCollectedItems() {SoftEntry sv;// 遍历queueOfGarbageCollectedEntries集合while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) {// 将已经被GC回收的value对象对应的缓存项清除delegate.removeObject(sv.key);}}private static class SoftEntry extends SoftReference<Object> {private final Object key;SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {// 指向value的引用是软引用,且关联了引用队列super(value, garbageCollectionQueue);// 强引用this.key = key;}}
}
WeakCache
WeakCache同SoftCache
/*** 弱引用缓存,可以看到代码和SoftCache如出一辙,就是SoftReference变成了WeakReference** Weak Reference cache decorator.* Thanks to Dr. Heinz Kabutz for his guidance here.** @author Clinton Begin*/
public class WeakCache implements Cache {private final Deque<Object> hardLinksToAvoidGarbageCollection;private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;private final Cache delegate;private int numberOfHardLinks;public WeakCache(Cache delegate) {this.delegate = delegate;this.numberOfHardLinks = 256;this.hardLinksToAvoidGarbageCollection = new LinkedList<>();this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();}@Overridepublic String getId() {return delegate.getId();}@Overridepublic int getSize() {removeGarbageCollectedItems();return delegate.getSize();}public void setSize(int size) {this.numberOfHardLinks = size;}@Overridepublic void putObject(Object key, Object value) {removeGarbageCollectedItems();delegate.putObject(key, new WeakEntry(key, value, queueOfGarbageCollectedEntries));}@Overridepublic Object getObject(Object key) {Object result = null;@SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cacheWeakReference<Object> weakReference = (WeakReference<Object>) delegate.getObject(key);if (weakReference != null) {result = weakReference.get();if (result == null) {delegate.removeObject(key);} else {synchronized (hardLinksToAvoidGarbageCollection) {hardLinksToAvoidGarbageCollection.addFirst(result);if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {hardLinksToAvoidGarbageCollection.removeLast();}}}}return result;}@Overridepublic Object removeObject(Object key) {removeGarbageCollectedItems();return delegate.removeObject(key);}@Overridepublic void clear() {synchronized (hardLinksToAvoidGarbageCollection) {hardLinksToAvoidGarbageCollection.clear();}removeGarbageCollectedItems();delegate.clear();}private void removeGarbageCollectedItems() {WeakEntry sv;while ((sv = (WeakEntry) queueOfGarbageCollectedEntries.poll()) != null) {delegate.removeObject(sv.key);}}private static class WeakEntry extends WeakReference<Object> {private final Object key;private WeakEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {super(value, garbageCollectionQueue);this.key = key;}}
}
相关文章:

Mybatis源码(九)— chche
Mybatis中共有三级缓存,其中一级缓存默认开启,作用范围是在sqlSession对象(同一个会话),二级缓存需要手动配置开启,作用范围是在sqlSessionFactory对象下的同一个namespace范围(所以二级缓存是可…...

回溯法--N皇后问题
N皇后问题 一、问题描述二、示例2.1 四皇后的2个可行解2.2 过程图示 三、问题分析3.1涉及到的概念递归回溯 3.2 分析 四、 代码实现4.1 实现思路宏观:微观: 4.2 递归函数NS图4.3 代码 一、问题描述 1、按照国际象棋的规则,皇后可以攻击与之处…...

ajax请求
ajax的优点 可以无需刷新页面而与服务器进行通信允许你根据用户事件来更新部分页面内容 ajax的缺点 没有浏览历史,不能回退存在跨域问题SEO不友好 get请求 <button>点击发送请求</button><div id"result"></div><script>…...

K8S系列之污点和容忍度详细分析
架构图 本篇文档主要介绍污点和容忍度的关系。 污点和容忍度 污点顾名思义就是脏的东西,给节点添加污点来限制pod调度到该节点上,如果pod可以容忍这种污点就可以被调度到有污点的节点上,如果不能容忍就不能被调度到该节点上。 污点作用于节…...

【算法】Minimum Moves to Move a Box to Their Target Location 推箱子
文章目录 Minimum Moves to Move a Box to Their Target Location 推箱子问题描述:分析代码 Tag Minimum Moves to Move a Box to Their Target Location 推箱子 问题描述: 问题 「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓…...

决策引擎平台建设方案
文档修订历史 时间版本主要内容2023.05.12v1.0.0初始化 1. 概述 1.1 需求 1.1.1 需求背景 当同一个业务场景中,有非常多的业务分支后,需要有非常多的 if 判断,来承载这些简单的业务逻辑,但随着业务的发展,业务逐渐…...

SpringBoot Starter 作用及原理
本文会以 mybatis 为例,通过对比 mybatis-spring 和 mybatis-spring-boot-starter 代码示例,了解 Starter 的作用。并对 mybatis-spring-boot-starter 进行简单剖析,了解 Starter 原理。 下面还有投票,一起参与进来吧👍…...

【rust】| 05——语法基础 | 流程控制
系列文章目录 【rust】| 00——开发环境搭建 【rust】| 01——编译并运行第一个rust程序 【rust】| 02——语法基础 | 变量(不可变?)和常量 【rust】| 03——语法基础 | 数据类型 【rust】| 04——语法基础 | 函数 【rust】| 05——语法基础 | 流程控制 文章目录 流程控制1. 条…...

解决Makefile: recipe for target ‘xxx‘ failed
author daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 问题 在android编译Kernel调用makefile引起的recipe for target 很多文章写的是由于编译文件路径引起或者是makefile代码中的空格引起的 分析 但是如果makefile文件不是手动配置的而且源代码提供的,…...

小黑子—多媒体技术与运用基础知识三:数字图形图像处理技术
多媒体技术与运用3.0 多媒体系列第三章1. 颜色科学1.1 颜色的性质1.1.1 颜色的物理性质1.1.2颜色三特性1.1.3三原色与三补色 1.2 颜色空间1.2.1 与设备无关的颜色空间1.2.1 与设备相关的颜色空间 1.3 常见的多媒体系统颜色空间1.3.1 RGB颜色空间1.3.2 CMYK颜色模型1.3.3 HSB颜色…...

Nginx实现ChatGPT API代理
文章目录 一、前言说明二、前置准备三、nginx配置三、代理域名用途 一、前言说明 本篇文章可以直接用于公司生产级的使用,所需要的资源直接改为公司级的即可平替使用文章均已通过实践应用,保证文章准确性,但因不同环境的不同可能效果不一致可…...

FileNotFoundError: [Errno 2] No such file or directory: ‘dot‘
FileNotFoundError: [Errno 2] No such file or directory: ‘dot’ 在绘制树形结构图的时候出现上述报错:已安装环境为ubuntu,python3.9 解决方案: 1、在终端输入sudo apt-get install graphviz,按回车键,输入密码&a…...

【分布族谱】正态分布和二项分布的关系
文章目录 正态分布二项分布验证 正态分布 正态分布,最早由棣莫弗在二项分布的渐近公式中得到,而真正奠定其地位的,应是高斯对测量误差的研究,故而又称Gauss分布。测量是人类定量认识自然界的基础,测量误差的普遍性&am…...

7.设计模式之责任链模式
前言 责任链,即将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递, 链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象。为了避免请求发送者与多个请求处理者耦合在…...

JAVA8的新特性——Stream
JAVA8的新特性——Stream 在这个深夜写下这篇笔记,窗外很安静,耳机里是《季节更替》,我感触还不是很多,当我选择封面图片的时候才发现我们已经渐渐远去,我们都已经奔赴生活,都在拼命想着去换一个活法&#…...

alias设置快捷键vim使用说明(解决服务器上输入长指令太麻烦的问题)
1. vi ~/.bashrc打开 2. (watch -n 1 gpustat 查看gpu使用情况 太麻烦)输入i进行编辑,最后一行输入 alias watchgpuwatch -n 1 gpustat alias gpuwatch -n 1 gpustat alias torch180source activate torch180 3. 按esc,然后输入:wq保存退出 4. source…...

英语基础句型之旅:从基础到高级
英语句型之旅:从基础到高级 一、起步:掌握英语基础句型 (Getting Started: Mastering Basic English Sentence Structures)1.1 英语句子的基本构成 (The Basic Components of English Sentences)1.2 五大基本句型解析 (Analysis of the Five Basic Sente…...

十四、Zuul网关
目录 一、API网关作用: 二、网关主要功能: 2.1、统一服务入口 2.2、接口鉴权 2.3、智能路由 2.4、API接口进行统一管理 2.5、限流保护 三、 新建一个项目作为网关服务器 3.1、项目中引入Zuul网关依赖 3.2、在项目application.yml中配置网关路由…...

5项目五:W1R3S-1(思路为主!)
特别注明:本文章只用于学习交流,不可用来从事违法犯罪活动,如使用者用来从事违法犯罪行为,一切与作者无关。 目录 前言 一、信息收集 二、网页信息的收集 三、提权 总结 前言 思路清晰: 1.信息收集,…...

Day958.代码的分层重构 -遗留系统现代化实战
代码的分层重构 Hi,我是阿昌,今天学习记录的是关于代码的分层重构的内容。 来看看如何重构整体的代码,也就是如何对代码分层。 一、遗留系统中常见的模式 一个学校图书馆的借书系统。当时的做法十分“朴素”,在点击“借阅”按钮…...

分子模拟力场
分子模拟力场 AMBER力场是在生物大分子的模拟计算领域有着广泛应用的一个分子力场。开发这个力场的是Peter Kollman课题组,最初AMBER力场是专门为了计算蛋白质和核酸体系而开发的,计算其力场参数的数据均来自实验值,后来随着AMBER力场的广泛…...

ERP 系统在集团化企业财务管理中的应用
(一)集团统一会计核算平台的构建原理及功能 第一,搭建集中统一会计核算平台的基础是确定财务组 织及岗位,在此基础上制定统一的会计核算政策、规范集中 基础数据、落实内控管理制度。 第二,具备了以上建立集中统一会计…...

达摩院开源多模态对话大模型mPLUG-Owl
miniGPT-4的热度至今未减,距离LLaVA的推出也不到半个月,而新的看图聊天模型已经问世了。今天要介绍的模型是一款类似于miniGPT-4和LLaVA的多模态对话生成模型,它的名字叫mPLUG-Owl。 论文链接:https://arxiv.org/abs/2304.14178…...

Group相关问题-组内节点限制移动范围
1.在节点中定义dragComputation,限制节点的移动范围 注意事项 组节点不定义go.Placeholder ,设置了占位符后组内节点移动将改变组节点位置dragComputation中自定义stayInGroup计算规则是根据groupNode的resizeObject计算 如果开启了resizable:true,建议指定其改变大的零部件r…...

程序员该如何学习技术
程序员该如何学习技术 前言 学习是第一生产力,我从来都是这么认为的,人只有只有不断地学习才能意识到自己的缺点和不足,身为程序员,我更认为人们应当抱着终身学习的想法实践下去,这是我所一直践行且相信的。 高处不胜寒…...

springboot+vue交流互动系统(源码+文档)
风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的交流互动系统。项目源码以及部署相关请联系风歌,文末附上联系信息 。 💕💕作者:风歌&a…...

【2023华为OD笔试必会25题--C语言版】《01 预定酒店》——排序、二分查找
本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的25道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...

C语言实现队列--数据结构
😶🌫️Take your time ! 😶🌫️ 💥个人主页:🔥🔥🔥大魔王🔥🔥🔥 💥代码仓库:🔥🔥魔…...

前端CSS经典面试题总结
前端CSS经典面试题总结 2.1 介绍一 下 CSS 的盒子模型?2.2 css 选择器优先级?2.3 垂直居中几种方式?2.4 简明说一下 CSS link 与 import 的区别和用法?2.5 rgba和opacity的透明效果有什么不同?2.6 display:none和visib…...

cookie、session、token的区别是什么
前言 今天就来说说session、cookie、token这三者之间的关系!最近这仨玩意搞得头有点大🤣 1.为什么会有它们三个? 我们都知道 HTTP 协议是无状态的,所谓的无状态就是客户端每次想要与服务端通信,都必须重新与服务端链接…...