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

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...