MyBatis中的多级缓存机制(一级缓存和二级缓存)

MyBatis中的多级缓存机制(一级缓存和二级缓存)

缓存(Cache)技术在互联网系统的开发过程中应用非常广泛。当系统中出现性能瓶颈时,很多场景都可以使用缓存技术来重构业务处理流程,从而获取性能的提升。缓存的实现方法可以有很多变化,但业界也存在一些主流的设计思想和工程实践。今天,我们将讨论其中具有代表性的多级缓存技术。

那么,什么是多级缓存呢?接下来,让我们先从多级缓存的基本结构开始说起。

多级缓存的基本结构

缓存的作用在于减少数据的访问时间和计算时间。具体表现上,通常是把来自持久化层或其它外部系统的数据转变为一系列可以直接从内存获取数据的过程。

在 Nginx、Redis、Tomcat 等组件中都可以存在缓存机制。我们无意对所有缓存机制进行展开,今天关注的是上图中应用程序层的缓存。这里的应用程序泛指诸如 Tomcat 等应用服务器,也包括像 Spring、Dubbo、MyBatis 等的开源框架,以及我们自己开发的业务系统。

如果我们具体分析应用层所具备的缓存实现技术,可以抽象出通用的缓存结构。下图就是一种常见的缓存的表现形式。

在这里插入图片描述

在上图中,当数据被表示为 Key-Value 对时,缓存会对 Key 施加一定的算法获取其 HashCode,再根据该 HashCode 所对应的索引找到 Value 在内存中的位置,并获取该 Value 值。

市面上各类缓存实现工具,尽管其支持的数据结构以及数据在内存中的分配和查找方式有所不同,但基本结构模型都与上图类似。从该图中,我们也认识到缓存本质上是一种时间换空间的实现方法。

现在,我们已经明确了单级缓存的基本结构,让我们对上图进行扩展和延伸,把讨论范围扩大到多级缓存。如果对应用程序层的缓存进行进一步分析,我们发现它存在一定的分级模式,这种分级模式通常包括两级,即一级缓存和二级缓存。

在这里插入图片描述

简单来说,所谓的一级缓存就是指一次请求(Request)级别或者会话(Session)级别的缓存。针对每次查询操作,一级缓存会把数据放在会话中,如果再次执行查询的话,就会直接从会话的缓存中获取数据,而不会去查询数据库。

而二级缓存的范围则更大一点,它是一种全局作用域的缓存。只要应用程序处于运行状态,那么所有请求和会话都可以使用。

多级缓存代表着一种架构设计的方法论,在多款开源框架中都有对应的实现方案。接下来,我们将基于 MyBatis 框架来分析它所具备的一级缓存和二级缓存。

MyBatis 多级缓存解析

在 MyBatis 中,缓存对应的接口是 Cache,框架本身内置了针对该接口的众多实现类。

在这里插入图片描述

上图中,除了 PerpetualCache 类之外,其他的实现类都是 Cache 的装饰器。PerpetualCache 是 MyBatis 中默认使用的缓存类型,其暴露的访问入口如下所示。

public class PerpetualCache {
    getId()//获取缓存 Id
    getSize()//获取缓存对象数量
	putObject()//添加缓存对象
	getObject()//获取缓存对象
	removeObject()//移除缓存对象
	clear()//清空缓存
}

在 PerpetualCache 的内部,保存缓存数据的只是一个 HashMap,因此是一种典型的基于内存的缓存实现方案。这里的几个方法也比较简单,所有对缓存的操作实际上就是对 HashMap 的操作。

在 MyBatis 中,一级缓存和二级缓存的背后用到的都是这个 PerpetualCache。让我们一起来看一下。

MyBatis 一级缓存解析

MyBatis 中存在一个配置项,用于指定一级缓存默认开启的级别,如下所示。

<setting name="localCacheScope" value="SESSION"/>

在 MyBatis 中一级缓存存在两个级别,即 SESSION 级和 STATEMENT 级,默认采用的是 SESSION。如果将其设置为 STATEMENT 级,可以理解为缓存只对当前 SQL 语句有效,Session 当中的缓存每次查询之后就会被清空。而如果是 SESSION 级,则查询结果一直会位于该 Session 中。

但是,要注意由于一级缓存是独立存在于每个 Session 内部的,因此,如果我们创建了不同的 Session,那么他们之间会使用不同的缓存。例如,完全一样的一个操作,如果在两个不同的 Session 中进行执行,那就意味着存在两份一样的缓存数据。但由于分别位于两个 Session 中,彼此之间的数据不会被共享。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 MyBatis 中,存在一个如下所示的 queryFromDatabase() 方法,该方法负责从数据库中查询数据,这个过程就用到了一级缓存。

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
	List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
	} finally {
	  //从缓存中移除对象
      localCache.removeObject(key);
    }
	//添加对象到缓存中
	localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
}

可以看到,一旦完成数据库查询,就会把从数据库中获取的数据保存在 localCache 中,而这个 localCache 就是一个 PerpetualCache 对象。

如果我们查看针对 SQL 的 update()、commit() 和 close() 等操作方法,会发现这些方法在执行完毕之后都会清空一级缓存。

通过前面的介绍,我们可以看到 MyBatis 的一级缓存是一个粗粒度的缓存,设计得比较简单。本质上它就是一个 HashMap,MyBatis 并没有对 HashMap 的大小进行管理,也没有缓存更新和过期的概念。这是因为一级缓存的生命周期很短,不会存活多长时间。

MyBatis 二级缓存解析

接下来让我们继续研究 MyBatis 中的另一种缓存表现形式,即二级缓存。相较一级缓存,MyBatis 的二级缓存使用方法有所不同,内部的实现逻辑也更为复杂。

与一级缓存不同,MyBatis 的二级缓存默认是不启用的,如果想要启动,则应该在配置文件中添加如下配置项。

<setting name="cacheEnabled" value="true"/>

上述配置方法是全局级别的,我们也可以在特定的查询级别使用二级缓存。MyBatis 专门提供了一个配置节点用于实现这一目标,这个配置节点可以定义缓存回收策略、缓存对象的数量上限等参数。

下图展示了 MyBatis 中二级缓存的生效范围。请注意,二级缓存是与命名空间(namespace)强关联的,即如果在不同的命名空间下存在相同的查询 SQL,这两者之间也是不共享缓存数据的。我们知道在 MyBatis 中,Configuration 对象管理着所有的配置信息,这就相当于所有的二级缓存全部位于 Configuration 之内。

首先明确一点,在 MyBatis 中,如果开启了二级缓存,不管配置的是哪种类型的执行过程,都会将该执行过程嵌套到 CachingExecutor 类中。

然后,我们注意到 CachingExecutor 中持有一个新的类 TransactionalCacheManager。当执行查询方法时,首先会通过 TransactionalCacheManager 获取到 Cache 对象,如果获取到的 Cache 对象为空,那么就执行查询操作,并把查询得到的数据放入 TransactionalCacheManager 中。

那么这里的 Cache 对象究竟是什么呢?实际上它是一个 TransactionalCache 对象。该对象中使用了 MyBatis 中的各种装饰器 Cache,并最终使用位于底层的 PerpetualCache 完成具体数据的缓存操作。

至此,整个二级缓存的使用过程得到了详细的解释,以 SQL 的 commit() 操作流程为例,整个过程的处理流程如下图所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结

今天的内容系统分析了日常开发过程中都会使用到的缓存机制,我们讨论了作为一个单级缓存应该具备的基本结构,也分析了应用程序级别常用的多级缓存机制。多级缓存设计思想在大量开源框架中都得到了应用,本讲我们基于 MyBatis 这款主流的 ORM 框架分析了它的一级缓存和二级缓存,并给出了对应的实现过程。尽管 MyBatis 所提供的多级缓存机制面向的是数据库访问领域,但我们可以借鉴背后的设计思想和方法,并应用到日常开发中。

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

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

相关文章

day14:RSYNC同步

一&#xff0c;概述 概述 rsync &#xff08;开源&#xff09;是一个高效的文件同步和传输工具&#xff0c;广泛用于 Linux 和 Unix 系统中。它可以在本地和远程系统之间同步文件和目录&#xff0c;同时支持增量备份&#xff0c;能够只传输更改过的文件部分&#xff0c;以减少…

Matlab实现白鲸优化算法(BWO)求解路径规划问题

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1内容介绍 白鲸优化算法&#xff08;BWO&#xff09;是一种受自然界白鲸捕食行为启发的新型优化算法&#xff0c;它通过模拟白鲸的群体捕猎策略和社会互动来探索问题的最优解。BWO因其强大的全局搜索能力和高效的局部搜索能…

python 模块和包、类和对象

模块 模块是包含 Python 代码的文件&#xff0c;通常用于组织相关的函数、类和其他语句。模块可以被导入并在其他 Python 文件中使用。 创建模块 假设你创建了一个名为 mymodule.py 的文件&#xff0c;内容如下&#xff1a; # mymodule.pydef greet(name): return f"…

SpringBoot节奏:Web音乐网站构建手册

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

使用Django REST framework构建RESTful API

使用Django REST framework构建RESTful API Django REST framework简介 安装Django REST framework 创建Django项目 创建Django应用 配置Django项目 创建模型 迁移数据库 创建序列化器 创建视图 配置URL 配置全局URL 配置认证和权限 测试API 使用Postman测试API 分页 过滤和排序…

MySQL 9从入门到性能优化-系统信息函数

【图书推荐】《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;》-CSDN博客 《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;&#xff08;数据库技术丛书&#xff09;》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) MySQL9数据库技术_夏天又到了…

芯片上音频相关的验证

通常芯片设计公司&#xff08;比如QUALCOMM&#xff09;把芯片设计好后交由芯片制造商&#xff08;比如台积电&#xff09;去生产&#xff0c;俗称流片。芯片设计公司由ASIC部门负责设计芯片。ASIC设计的芯片只有经过充分的验证&#xff08;这里说的验证是FPGA&#xff08;现场…

$tab的所有用法以及vue关闭页面的方法汇总

1、最简单粗暴的就是直接window.close(); 2.可以设置一个窗口的显示隐藏变量&#xff0c;比如点击新增按钮时&#xff0c;新增页面窗口就进行显示&#xff0c;点击关闭就把这个值置为flase 在最外层绑定open 初始值设为false 点击新增和修改按钮时&#xff0c;把状态置为true即…

深度学习(八) TensorFlow、PyTorch、Keras框架大比拼(8/10)

一、深度学习框架概述 深度学习框架在当今人工智能和机器学习领域中占据着至关重要的地位。其中&#xff0c;TensorFlow 由 Google 开发&#xff0c;自 2015 年发布以来&#xff0c;凭借其灵活的计算图、自动微分功能以及跨平台支持等特点&#xff0c;迅速成为主流深度学习框架…

<HarmonyOS第一课>HarmonyOS SDK开放能力简介的课后习题

不出户&#xff0c;知天下&#xff1b; 不窥牖&#xff0c;见天道。 其出弥远&#xff0c;其知弥少。 是以圣人不行而知&#xff0c;不见而明&#xff0c;不为而成。 本篇<HarmonyOS第一课>HarmonyOS SDK开放能力简介是简单介绍了HarmonyOS SDK&#xff0c;不需要大家过多…

WPF自定义日历控件Calendar 的方法

推荐下载地址 https://www.haolizi.net/example/view_2107.html <UserControl.Resources><local1:DayConverter x:Key"DayConverter"/><!--导入转换器--><Style x:Key"CalendarStyle1"TargetType"{x:Type Calendar}">&…

园区网典型技术应用

工厂、政府机关、商场、写字楼、校园、公园等&#xff0c;这些场所内为了实现数据互通而搭建的网络都可以称之为园区网 1. 园区网络架构与常见技术概述 某高校校园网络采用三层架构&#xff0c;核心层和汇聚层各有其明确的职责&#xff1a; 核心层&#xff1a;部署两台核心交…

计算机考研,选择西安交通大学还是哈工大?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 经过全面分析&#xff0c;2025年考研西安交通大学和哈尔滨工业大学计算机专业的报考难度对比如下&#xff1a; 西安交通大学计算机专业 > 哈尔滨工业大学计算机专业 对于想要报考985高校计算机专业但核心目标是优…

3D游戏阴影技术综合指南

在维姆文德斯 (Wim Wenders) 的优秀作品《完美的日子》 (Perfect Days) 的结尾&#xff0c;男主角平山 (Hirayama) 在桥下喝啤酒&#xff0c;因为他看到一个商人在追求他的暗恋对象。突然&#xff0c;商人在桥下加入了他。事实证明&#xff0c;事情并没有那么简单&#xff0c;但…

Unity 2D寻路导航 NavMeshPlus解决方案

插件的github主页 h8man/NavMeshPlus: Unity NavMesh 2D Pathfinding 这个插件是基于新版3D寻路导航制作的&#xff0c;所以你可能需要看一下这篇文章 新旧Navmash 寻路导航组件对比 附使用案例与实用教程链接-CSDN博客 这行代码agent.updateUpAxis false 一定要为代理单位…

K8s企业应用之容器化迁移

#作者&#xff1a;曹付江 K8s企业应用之容器化迁移 Kubernetes&#xff08;K8s&#xff09;中的企业应用容器化迁移是一个复杂但重要的过程&#xff0c;平滑的迁移应用&#xff0c;可以让开发、运维、测试人员循序渐进的学习和掌握Kubernetes&#xff0c;通常包括以下步骤&am…

Flash的语音ic型号有哪些?

深圳唯创知音电子有限公司在语音技术领域具有深厚的积累&#xff0c;其Flash语音IC产品凭借高性能和广泛的应用领域&#xff0c;在市场上占据了一席之地。以下是对该公司Flash语音IC产品的详细介绍&#xff1a; 一、产品概述 Flash语音IC是一种采用Flash存储技术的语音芯片&…

vscode摸鱼学习插件开发

不知道大家在摸鱼的时候&#xff0c;会不会想要学习&#xff1f; 或者有没有考公人&#xff0c;下班要学习的&#xff1f; 上班时间摸鱼&#xff0c;下班时间不够学习&#xff1f; 为此&#xff0c;我决定开发一个vscode插件&#xff0c;来刷粉笔题 粉笔插件名称&#xff1a;…

PPT制作新选择:本地部署PPTist结合内网穿透实现实时协作和远程使用

文章目录 前言1. 本地安装PPTist2. PPTist 使用介绍3. 安装Cpolar内网穿透4. 配置公网地址5. 配置固定公网地址 &#x1f4a1; 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击跳转到网站】 前…

文件上传知识梳理:原理、工具、绕过、利用与防御

文章简介&#xff1a; 本文全面梳理了文件上传相关知识&#xff0c;包括文件上传漏洞的原理及危害&#xff0c;介绍了 Webshell 相关工具&#xff08;如冰蝎、哥斯拉、蚁剑&#xff09;&#xff0c;详细阐述了文件上传绕过检测的多种方法&#xff08;前端检测、服务端检测的各…