Mybatis二级缓存

news/2024/5/6 18:52:35/文章来源:https://blog.csdn.net/jiayoubaobei2/article/details/129272770

目录

二级缓存的定义

二级缓存扩展性需求

二级缓存的结构

SynchronizedCache线程同步缓存区

LoggingCache统计命中率以及打印日志

ScheduledCache过期清理缓存区

LruCache(最近最少使用)防溢出缓存区

FifoCache(先进先出)防溢出缓存区

二级缓存的使用(命中条件)

二级缓存的配置

二级缓存为什么要提交之后才能命中缓存?

二级缓存执行流程


二级缓存的定义

二级缓存也称作是应用级缓存,与一级缓存不同的是它的作用范围是整个应用,而且可以跨线程使用。所以二级缓存有更高的命中率,适合缓存一些修改比较少的数据。

二级缓存扩展性需求

 二级缓存的生命周期是整个应用,所以必须限制二级缓存的容量,在这里mybatis使用的是溢出淘汰机制。而一级缓存是会话级的生命周期非常短暂是没有必要实现这些功能的。相比较之下,二级缓存机制更加完善。

二级缓存的结构

二级缓存在结构设计上采用装饰器+责任链模式

1)二级缓存是如何组装这些装饰器的呢?

这里我们先介绍一下CacheBuilder类顾名思义这是一个缓存构建类。该类就是二级缓存的构建类里面定义了一些上图装饰器类型的属性,以及构建组合这些装饰器的行为。

源码分析:

public Cache build() {this.setDefaultImplementations();Cache cache = this.newBaseCacheInstance(this.implementation, this.id);this.setCacheProperties((Cache)cache);if (PerpetualCache.class.equals(cache.getClass())) {Iterator var2 = this.decorators.iterator();while(var2.hasNext()) {Class<? extends Cache> decorator = (Class)var2.next();cache = this.newCacheDecoratorInstance(decorator, (Cache)cache);this.setCacheProperties((Cache)cache);}cache = this.setStandardDecorators((Cache)cache);} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {cache = new LoggingCache((Cache)cache);}return (Cache)cache;
}private void setDefaultImplementations() {if (this.implementation == null) {this.implementation = PerpetualCache.class;if (this.decorators.isEmpty()) {this.decorators.add(LruCache.class);}}}private Cache setStandardDecorators(Cache cache) {try {MetaObject metaCache = SystemMetaObject.forObject(cache);if (this.size != null && metaCache.hasSetter("size")) {metaCache.setValue("size", this.size);}if (this.clearInterval != null) {cache = new ScheduledCache((Cache)cache);((ScheduledCache)cache).setClearInterval(this.clearInterval);}if (this.readWrite) {cache = new SerializedCache((Cache)cache);}Cache cache = new LoggingCache((Cache)cache);cache = new SynchronizedCache(cache);if (this.blocking) {cache = new BlockingCache((Cache)cache);}return (Cache)cache;} catch (Exception var3) {throw new CacheException("Error building standard cache decorators.  Cause: " + var3, var3);}
}

SynchronizedCache线程同步缓存区

实现线程同步功能,与序列化缓存区共同保证二级缓存线程安全。若blocking=false关闭则SynchronizedCache位于责任链的最前端,否则就位于BlockingCache后面而BlockingCache位于责任链的最前端,从而保证了整条责任链是线程同步的。

源码分析:只是对于操作缓存的方法进行了线程同步功能

LoggingCache统计命中率以及打印日志

统计二级缓存命中率并输出打印,由以下源码可知:日志中出现了“Cache Hit Ratio”便表示命中了二级缓存。

源码分析:

public class LoggingCache implements Cache {private final Log log;private final Cache delegate;protected int requests = 0;protected int hits = 0;public LoggingCache(Cache delegate) {this.delegate = delegate;this.log = LogFactory.getLog(this.getId());}public Object getObject(Object key) {++this.requests;//执行一次查询加一次Object value = this.delegate.getObject(key);//查询缓存中是否已经存在if (value != null) {++this.hits;//命中一次加一次}if (this.log.isDebugEnabled()) {//开启debug日志this.log.debug("Cache Hit Ratio [" + this.getId() + "]: " + this.getHitRatio());}return value;}private double getHitRatio() {//计算命中率return (double)this.hits / (double)this.requests;//命中次数:查询次数}
}

ScheduledCache过期清理缓存区

@CacheNamespace(flushInterval=100L)设置过期清理时间默认1个小时,

若设置flushInterval为0代表永远不进行清除。

源码分析:操作缓存时都会进行检查缓存是否过期

public class ScheduledCache implements Cache {private final Cache delegate;protected long clearInterval;protected long lastClear;public ScheduledCache(Cache delegate) {this.delegate = delegate;this.clearInterval = 3600000L;this.lastClear = System.currentTimeMillis();}public void clear() {this.lastClear = System.currentTimeMillis();this.delegate.clear();}private boolean clearWhenStale() {
//判断当前时间与上次清理时间差是否大于设置的过期清理时间if (System.currentTimeMillis() - this.lastClear > this.clearInterval) {this.clear();//一旦进行清理便是清理全部缓存return true;} else {return false;}}
}

LruCache(最近最少使用)防溢出缓存区

内部使用链表(增删比较快)实现最近最少使用防溢出机制

源码分析:

public void setSize(final int size) {this.keyMap = new LinkedHashMap<Object, Object>(size, 0.75F, true) {private static final long serialVersionUID = 4267176411845948333L;protected boolean removeEldestEntry(Entry<Object, Object> eldest) {boolean tooBig = this.size() > size;if (tooBig) {LruCache.this.eldestKey = eldest.getKey();}return tooBig;}};
}
//每次访问都会遍历一次key进行重新排序,将访问元素放到链表尾部。
public Object getObject(Object key) {this.keyMap.get(key);return this.delegate.getObject(key);
}

FifoCache(先进先出)防溢出缓存区

源码分析:内部使用队列存储key实现先进先出防溢出机制。

public class FifoCache implements Cache {private final Cache delegate;private final Deque<Object> keyList;private int size;public FifoCache(Cache delegate) {this.delegate = delegate;this.keyList = new LinkedList();this.size = 1024;}public void putObject(Object key, Object value) {this.cycleKeyList(key);this.delegate.putObject(key, value);}public Object getObject(Object key) {return this.delegate.getObject(key);}private void cycleKeyList(Object key) {this.keyList.addLast(key);if (this.keyList.size() > this.size) {//比较当前队列元素个数是否大于设定值Object oldestKey = this.keyList.removeFirst();//移除队列头元素this.delegate.removeObject(oldestKey);//根据移除元素的key移除缓存区中的对应元素}}
}

二级缓存的使用(命中条件)

1)会话提交后

2)sql语句、参数相同

3)相同的statementID

4)RowBounds相同

注意:设置为自动提交事务并不会命中二级缓存。

二级缓存的配置

二级缓存为什么要提交之后才能命中缓存?

会话一与会话二原本是两条隔离的事务,但由于二级缓存的存在导致彼此可见会发生脏读。若会话二的修改直接填充到二级缓存,会话一查询时缓存中存在即直接返回数据,此时会话二回滚会话一读到的数据就是脏数据。为了解决这一问题mybatis二级缓存机制就引入了事务管理器(暂存区),所有变动的数据都会暂时存放到事务管理器的暂存区中,只有执行提交动作后才会真正的将数据从暂存区中填充到二级缓存中。

1)会话:事务缓存管理器:暂存区=1:1:N

2)暂存区:缓存区=1:1(一个暂存区对应唯一一个缓存区)

3)会话关闭,事务缓存管理器也会关闭,暂存区也会被清空

4)一个事务缓存管理器管理多个暂存区

5)有多少个暂存区取决于你访问了多少个Mapper文件(缓存的key是Mapper文件全路径ID)

二级缓存执行流程

1)查询是实时查询缓存区的。

2)所有对二级缓存的实时变动都是通过暂存区来实现的。

3)暂存区清理完会进行标识,但此时二级缓存中数据并未清理,只有执行commit后才会真正清理二级缓存中的数据。

4)查询会实时查询缓存区,若暂存区清理标识为true就算从缓存区中查询到数据也会返回一个null,重新查询数据库(暂存区清理标识为true也会返回null是为了防止脏读,一旦提交清空掉二级缓存中的数据此时读取到的就是脏数据,因此返回null重新查询数据库得到的才是正确数据)。

源码分析:

a1、若开启二级缓存进行查询方法的时候会走到类CachingExecutor中的query方法

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {Cache cache = ms.getCache();//获得Cacheif (cache != null) {this.flushCacheIfRequired(ms);//判断是否配置了flushCache=true,若配置了清空暂存区if (ms.isUseCache() && resultHandler == null) {this.ensureNoOutParams(ms, boundSql);List<E> list = (List)this.tcm.getObject(cache, key);//获得缓存if (list == null) {//若为空查询数据库并将数据填充到暂存区list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);this.tcm.putObject(cache, key, list);}return list;}}return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

a2、根据上一步中的tcm.getObject(cache, key)方法查询二级缓存

public Object getObject(Object key) {Object object = this.delegate.getObject(key);//查询二级缓存if (object == null) {//为空也是为了先设置一个值防止缓存穿透this.entriesMissedInCache.add(key);}//判断暂存区清空标识是否为true,若为true直接返回null重新查询数据库防止脏读return this.clearOnCommit ? null : object;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_75828.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用netlify实现自动化部署前端项目(无服务器版本)

介绍 本文以 github仓库进行介绍关联netlify的无服务前端自动化部署。用途&#xff1a;个人网站设计、小游戏等当然这只是让你入门~具体细节等待你自己去探索 实现 打开官方网站 如果没有注册过的账户&#xff0c;你需要使用 github 去进行登录。注册完成后会自动给你提示填…

866363-70-4,N3-C5-NHS ester,叠氮-C5-NHS 主要物理性质分享

●外观以及性质&#xff1a;Azido-Aca-NHS淡黄色或无色油状&#xff0c;叠氮化物可以与炔烃、DBCO和BCN进行铜催化的点击化学反应。NHS酯可以与胺基反应&#xff0c;形成稳定的酰胺键。●中文名&#xff1a;叠氮-C5-NHS ester&#xff0c;6-叠氮己酸活性酯●英文名&#xff1a;…

阶乘后的零[挖掘规律+动态规划]

挖掘规律 动态规划前言一、阶乘后的零二、挖掘规律1、动态规划2、直接寻找5的个数总结参考资料前言 想要计算阶乘后的0有多少&#xff0c;可以直接算出阶乘值&#xff0c;再不断对10取余。但是如果n比较大&#xff0c;这种方法是根本行不通的&#xff0c;只能挖掘规律。 一、…

数据挖掘1/13

文章目录教材&#xff0c;考核&#xff0c;软件现在数据是ZB时代数据挖掘公司3类数据挖掘数据挖掘技术&#xff08;5个&#xff09;分类&#xff1a;找因变量y无监督聚类数据分析 数据挖掘教材&#xff0c;考核&#xff0c;软件 教材 考核 软件&#xff1a;jupyter 和spss mod…

十四、MyBatis的逆向工程

逆向工程&#xff1a; 根据数据库表逆向生成Java的pojo类&#xff0c;SqlMapper.xml文件&#xff0c;以及Mapper接口类等。 借助别人写好的逆向工程插件。 使用这个插件的话&#xff0c;需要给这个插件配置哪些信息&#xff1f; pojo类名、包名以及生成位置。SqlMapper.xml文…

EPICS motor模块

一、概要 1&#xff09; 在EPICS motor模块中的是什么并且它为了什么&#xff1f; 2&#xff09; 支持的电机控制器和模型 3&#xff09;电机记录特性 4&#xff09;配置示例 5&#xff09;反馈 6&#xff09; 重试 7&#xff09; 回程差矫正 8&#xff09;发行 二、术…

webrtc拥塞控制算法对比-GCC vs BBR vs PCC

1.前言现有集成在webrtc中的拥塞控制算法有三种, 分别是: 谷歌自研发的gcc, 谷歌自研发的BBR算法, 斯坦福大学提出的基于机器学习凸优化的PCC算法. 本文将探讨一下三个算法的区别和优缺点。2.背景迈聆会议从17年到现在, 一直使用的是基于谷歌的gcc算法自研的Omcc算法(optimizat…

[软件测试]如何使用Eclipse导入项目并打开

&#x1f9d1;‍&#x1f393;个人介绍&#xff1a;大二软件生&#xff0c;现学JAVA、Linux、MySQL、算法 &#x1f4bb;博客主页&#xff1a;渡过晚枫渡过晚枫 &#x1f453;系列专栏&#xff1a;[编程神域 C语言]&#xff0c;[java/初学者]&#xff0c;[蓝桥杯] &#x1f4d…

数据结构与算法基础-学习-14-线性表之串

一、串的定义由0-n个字符组成的有限序列。&#xff08;n>0&#xff09;二、串的相关术语1、子串串中任意个连续字符组成的子序列成为该串的子串。2、主串包含子串的串成为主串。3、字符位置字符在序列中的序号为该字符在串中的位置。4、子串位置子串第一个字符在主串中的位置…

[Java·算法·中等]LeetCode17. 电话号码的字母组合

每天一题&#xff0c;防止痴呆题目示例分析思路1题解1分析思路2题解2题目 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。…

CSS简单使用

凡是html中的标签都可以进行选中&#xff0c;p代表标签中所有的p标签都遵从以上格式。<!DOCTYPE html> <html lang"en"> <head><style type"text/css">p{background-color: red;font-size: 40px;}.p1{font-family:楷体;}</styl…

爆品分析第4期 | 从周销12件到3700+件,这款收腰裤热度和口碑都爆了!

衣食住行&#xff0c;衣是排在第一位的&#xff0c;作为复购率最高的类目之一&#xff0c;服饰一直是TikTok上电商选品的风向标&#xff0c;是衡量电商发展情况的重要参考指标。随着疫情的结束和经济的日渐好转&#xff0c;消费者对服装类的需求上升。除了时装、T恤等日常消费的…

关于PPP-RTK技术优势的一些思考与总结

文章目录一、前言二、SSR修正与PPP三、RTK与PPP-RTK的对比四、PPP-RTK的技术优势五、总结参考文章欢迎关注个人公众号&#xff1a;导航员学习札记 一、前言 感觉近几年PPP和PPP-RTK一直都是GNSS比较火的方向&#xff0c;也有越来越多的国内外厂商提供相关服务&#xff0c;播发…

HTTP2.0协议学习

背景 在优化页面加载速度的时候&#xff0c;发现了HTTP1.1并发数的限制&#xff0c;为了解除这个限制&#xff0c;准备把网站协议升级到HTTP2.0. 之前在学习《趣谈网络协议》的时候&#xff0c;有学习过HTTP2.0协议&#xff0c;但是没有输出成文档&#xff0c;因此借这个机会&…

DIY-BETAFPV和DIY(ESP-01F+E19-900M20S2模块)915MHz信号测试对比

DIY-BETAFPV和DIY&#xff08;ESP-01FE19-900M20S2模块&#xff09;915MHz信号测试对比1. 前提条件2. 实测效果2.1 起点附近&#xff08;距离3m左右&#xff09;2.2 30m米距离&#xff08;树梢&#xff09;2.3 80米距离3. 整体比较4. PCBA分析4.1 DIY-BETAFPV4.2 DIY&#xff0…

阿里云服务器ECS的功能特性有哪些?

本文介绍云服务器ECS的功能特性&#xff0c;帮助您更好地了解和使用云服务器ECS。 1、实例 实例是云上的虚拟计算服务器&#xff0c;内含vCPU、内存、操作系统、网络、磁盘等基础组件。您可以使用阿里云提供的控制台、API等管理工具创建和管理ECS实例&#xff0c;像使用本地服…

Java-封装、继承、多态

封装 访问控制权限又成为“封装”&#xff0c;是面向对象三大特征中的一种。核心是&#xff0c;只对需要的类可见。 继承 继承是所有OOP&#xff08;Object Oriented Programming&#xff09;语言和Java语言都不可或缺的一部分。 只要创建一个类&#xff0c;就隐式继承自Obje…

openpnp - configure - 矫正里程碑

文章目录openpnp - configure - 矫正里程碑概述备注ENDopenpnp - configure - 矫正里程碑 概述 进入矫正里程碑了 查找问题 现在第一个问题是X轴的齿隙矫正 根据提示, 将顶部相机移动到主基准点上, 选择容差(就选用默认的0.025), 开始矫正. 正好开机后, 使能了视觉原点归零. …

Puppeteer项目结构梳理

最近接触了一个个人感觉很奈斯的项目&#xff0c;故记录思路如下&#xff1a; puppeteer项目梳理&#xff1a; 入口文件 run.js 入口命令 node run.js YourConfig.json 1、我们可以在自己的config.json里面设置好 ①、登录的用户名密码;aws或其它服务器的access等id,accessKey…

linux--多线程(一)

文章目录Linux线程的概念线程的优点线程的缺点线程异常线程的控制创建线程线程ID以及进程地址空间终止线程线程等待线程分离线程互斥进程线程间的互斥相关概念互斥量mutex有线程安全问题的售票系统查看ticket--部分的汇编代码互斥量的接口互斥量实现原理探究可重入和线程安全常…