当前位置: 首页 > news >正文

【MyBatis】验证多级缓存及 Cache Aside 模式的应用

文章目录

    • 前言
    • 1. 多级缓存的概念
      • 1.1 CPU 多级缓存
      • 1.2 MyBatis 多级缓存
    • 2. MyBatis 本地缓存
    • 3. MyBatis 全局缓存
      • 3.1 MyBatis 全局缓存过期算法
      • 3.2 CacheAside 模式
    • 后记
      • MyBatis 提供了缓存切口, 采用 Redis 会引入什么问题?
      • 万一遇到需强一致场景,如何增强?

前言

MyBatis 官方文档 中文版本没有翻译cache的部分,网上资料比较杂。
这里使用 Spock 测试框架验证下多级缓存,并探索 Mybatis 的 CacheAside 模式。注意:

  • 本文用 本地缓存 表示一级缓存,全局缓存 表示二级缓存
  • 用例仓库

1. 多级缓存的概念

多级缓存可以联系CPU的结构,离核心约近的一致性越高。

1.1 CPU 多级缓存

在这里插入图片描述

1.2 MyBatis 多级缓存

本地缓存默认开启,全局缓存需要使用 <cache/> 开启

By default, just local session caching is enabled that is used solely to cache data for the duration of a session. To enable a global second level of caching you simply need to add one line to your SQL Mapping file:

<mapper namespace="com.james.mapper.FileCacheMapper"><cache/> <!-- 声明该标签,全局缓存开启 --><select id="select" resultType="java.lang.String">SELECT file_name FROM file</select>
</mapper>

2. MyBatis 本地缓存

用 Spring 注入的 mapper,调用一次select方法就会产生一个 sqlSession,没有利用到本地缓存。

    def "未使用事务,第二次查询,不命中本地缓存"() {given:def list1 = mapper.select()def list2 = mapper.select()expect:list1 !== list2}

用事务包裹后,两次 select 共用一个 sqlSession,缓存命中

 	def "使用事务,命中缓存"() {given:def list1 = []def list2 = []when:transaction.execute {list1 = mapper.select()list2 = mapper.select()}then:// 同一个事务使用同一个SqlSession,若引用相同则认为命中缓存list1 === list2}

note: groovy 中 list1 === list2 表示引用相同,list1 == list2 表示两个列表的内容相同

3. MyBatis 全局缓存

上文说到,没有事务保护的 select方法调用无法公用一个 sqlSession,所以利用不了本地缓存。
全局缓存的范围更大,只要是同一个mapper的调用,都会被缓存。

    def "全局缓存默认关闭,需要在xml文件中使用 <cache/> 标签启用"() {given:def list1  = fileCacheMapper.select()def list2  = fileCacheMapper.select()expect:// 由于 SerializedCache.java:64 使用的是由byte[]序列化方式存储元素,所以实例的地址必然不同list1 !== list2list1 == list2}

3.1 MyBatis 全局缓存过期算法

在这里插入图片描述
值得关注的是 SOFT 和 WEAK 的类型,对应Java中软引用和弱引用。
软引用是在内存不足时GC可以回收,弱引用是下次GC即可回收(比软引用)积极。

3.2 CacheAside 模式

以下是 Mybatis 默认的全局缓存失效模式,也就是 Cache Aside 模式的应用。

  • 查询的时候,如果没有缓存,则写入。
  • 任何数据操作,使缓存失效。
<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>

后记

Cache Aside 并不能保证强一致性,不然也就不会有 Paxos 这种复杂的共识算法了。 —— 《凤凰架构》

MyBatis 提供了缓存切口, 采用 Redis 会引入什么问题?

  • 多实例之间缓存重复的失效问题,查询时竞争写缓存的问题。
  • ORM框架与中间件耦合,违反单一职责。

万一遇到需强一致场景,如何增强?

  • 两个查询请求同时到来,此时缓存为空,需要将MySql数据写入缓存。此时会出现竞争写缓存的情况。用写锁来保证缓存内的数据跟数据库保持一致。
public void query() {if (cache 命中) {retrun cache} 获取缓存写锁if (获取锁失败) {return 查数据库} 查数据库写缓存释放缓存写锁
}

相关文章:

【MyBatis】验证多级缓存及 Cache Aside 模式的应用

文章目录 前言1. 多级缓存的概念1.1 CPU 多级缓存1.2 MyBatis 多级缓存 2. MyBatis 本地缓存3. MyBatis 全局缓存3.1 MyBatis 全局缓存过期算法3.2 CacheAside 模式 后记MyBatis 提供了缓存切口&#xff0c; 采用 Redis 会引入什么问题&#xff1f;万一遇到需强一致场景&#x…...

学习ASP.NET Core的身份认证(基于Session的身份认证3)

开源博客项目Blog中提供了另一种访问控制方式&#xff0c;其基于自定义类及函数的特性类控制访问权限。本文学习并测试开源博客项目Blog的访问控制方式&#xff0c;测试程序中直接复用开源博客项目Blog中的相关类及接口定义&#xff0c;并在其上调整判断逻辑。   首先是接口A…...

速盾:高防 CDN 可以配置客户端请求超时配置?

在高防 CDN&#xff08;Content Delivery Network&#xff0c;内容分发网络&#xff09;的运行管理中&#xff0c;客户端请求超时配置是一项重要的功能设定&#xff0c;它对于优化网络资源分配、保障服务质量以及维护系统稳定性有着关键意义。 一、客户端请求超时配置的概念 …...

DRM(数字权限管理技术)防截屏录屏----ffmpeg安装

提示&#xff1a;ffmpeg安装 文章目录 [TOC](文章目录) 前言一、下载二、配置环境变量三、运行ffmpeg四、文档总结 前言 FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的…...

使用PyQt5开发一个GUI程序的实例演示

一、安装Python 下载安装到这个目录 G:\Python38-32 安装完成有这些工具&#xff0c;后面备用&#xff1a; G:\Python38-32\Scripts\pyrcc5.exe G:\Python38-32\Scripts\pyuic5.exe 二、PyQt环境配置 pip install PyQt5 pip install pyqt5-tools 建议使用国内源&#xff0c…...

【VUE3】【Naive UI】<NCard> 标签

【Vue3】【Naive UI】 标签 title 属性bordered 属性header-style 和 body-style 属性footer 属性actions 属性hoverable 属性loading 属性size 属性type 属性cover 和 avatar 属性description 属性style 属性 【VUE3】【Naive UI】&#xff1c;NCard&#xff1e; 标签 【VUE3】…...

选择排序之大根堆

大根堆&#xff1a;树的根节点大于左右子树的结点值&#xff0c;这样就能保证每次从树根取的是最大值 灵魂在于HeadAdjust函数&#xff0c;以某节点为树根通过下落调整为大根堆&#xff0c; 建树思想 就是&#xff0c;从最后一个非终端结点开始调整以该结点为根的子树&#x…...

AI的魔力:如何为开源软件注入智慧,开启无限可能

“AI的魔力&#xff1a;如何为开源软件注入智慧&#xff0c;开启无限可能” 引言&#xff1a; 在科技发展的浪潮中&#xff0c;开源软件生态一直扮演着推动创新与共享的重要角色。从Linux到Python&#xff0c;开源项目赋予了开发者全球协作的机会&#xff0c;推动了技术的飞速…...

如何在 VPS 上使用 Git 设置自动部署

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 介绍 要了解 Git 的基本知识以及如何安装&#xff0c;请参考介绍教程。 本文将教你如何在部署应用程序时使用 Git。虽然有许多使用 Gi…...

Linux下的三种 IO 复用

目录 一、Select 1、函数 API 2、使用限制 3、使用 Demo 二、Poll 三、epoll 0、 实现原理 1、函数 API 2、简单代码模板 3、LT/ET 使用过程 &#xff08;1&#xff09;LT 水平触发 &#xff08;2&#xff09;ET边沿触发 4、使用 Demo 四、参考链接 一、Select 在…...

通过 SSH 进行WordPress网站的高级服务器管理

我在管理hostease的服务器时&#xff0c;时常需要通过SSH登录服务器进行修改。而在网站管理中&#xff0c;SSH不仅是一个基础工具&#xff0c;更是高级用户用来精细化管理和优化服务器的重要工具。通过SSH&#xff0c;你可以深入监控服务器的性能、精细管理系统资源&#xff0c…...

速盾高防cdn支持移动端独立缓存

随着移动互联网的快速发展&#xff0c;移动端网页访问量也越来越大。然而&#xff0c;移动端的网络环境相对不稳定&#xff0c;用户体验可能会受到影响。因此&#xff0c;使用高防CDN来加速移动端网页访问&#xff0c;成为越来越多网站运营者的首选。 速盾高防CDN是一种分布式…...

PMP–一、二、三模、冲刺–分类–8.质量管理

文章目录 技巧五、质量管理 一模8.质量管理--质量管理计划--质量管理计划包括项目采用的质量标准&#xff0c;到底有没有满足质量需求&#xff0c;看质量标准即可。6、 [单选] 自项目开始以来&#xff0c;作为项目经理同事的职能经理一直公开反对该项目&#xff0c;在讨论项目里…...

如何快速使用Unity 的UPR---1资源检测保姆级

关于我们的性能检测工具已经有很多了&#xff0c;比如UWA的或者是我们的Unity 的UPR 都是很好的&#xff0c;今天说一下UPR吧 官方网址 &#xff1a;UPR - Unity专业性能优化工具 这个是官方给的Demo 选择你的平台就可以 这个可以作为一个参考但是不是很建议用官方的因为我们…...

pytorch中的.clone() 和 .detach()

在PyTorch中&#xff0c;.clone() 和 .detach() 是两个用于处理张量&#xff08;Tensor&#xff09;的方法&#xff0c;它们各自有不同的用途&#xff1a; .clone()&#xff1a; .clone() 方法用于创建一个张量的副本&#xff08;深拷贝&#xff09;。这意味着原始张量和新张量…...

三十二:网络爬虫的工作原理与应对方式

随着互联网的快速发展&#xff0c;网络爬虫&#xff08;Web Crawlers&#xff09;作为一种自动化工具&#xff0c;被广泛应用于搜索引擎、数据采集、网站监控等领域。网络爬虫的作用是通过自动化程序&#xff0c;模拟人类浏览网页的行为&#xff0c;自动下载和解析网页内容&…...

nodejs相关知识介绍

1、nodejs官方文档&#xff1a; https://nodejs.org/zh-cn nodejs可以用nvm进入安装&#xff1b; 2、npm说明&#xff1a; npm官方教程&#xff1a;https://npm.p2hp.com/ npm是 Node.js 的标准包管理器&#xff0c;也就是说nodejs安装好&#xff0c;npm也就安装好了&#…...

MySQL排它锁

MySQL排它锁原理 MySQL中的排它锁&#xff08;Exclusive Lock&#xff09;&#xff0c;也称为独占锁&#xff0c;是一种确保在事务期间&#xff0c;其他事务无法对锁定数据进行读取或修改的锁机制。当一个事务对某一行数据加上排它锁后&#xff0c;其他事务无法对该行数据进行…...

HarmonyOS4+NEXT星河版入门与项目实战(22)------动画(属性动画与显示动画)

文章目录 1、属性动画图解2、案例实现-小鱼移动游戏1、代码实现2、代码解释3、资源图片4、实现效果3、显示动画4、案例修改-显示动画5、总结1、属性动画图解 这里我们用一张完整的图来汇整属性动画的用法格式和使用的主要属性范围,如下所示: 2、案例实现-小鱼移动游戏 1、代…...

Vue3 Ts 如何获取组件的类型

vue3 Ts ref 子组件 1、默认写法 typeof&#xff1a;获取ts类型 InstanceType&#xff1a;获取模版的实例 <tempolate><myComponent ref"myCompRef"> </tempolate><script setup lang"ts"> import { ref } from "vue&quo…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...