Mybatis(六)缓存

缓存是Mybatis中非常重要的特性,Mybatis的一级缓存基于SqlSession实现,二级缓存基于Mapper实现。

一、缓存的使用

一级缓存默认开启,Mybatis提供了一个配置参数localCacheScope来控制一级缓存的级别,该参数的取值可以是session、statement等,当取值为session时,缓存对整个sqlsession有效,只有执行DML(更新)语句时缓存才会被清除,当取值为statement是,缓存只对当前执行的语句生效,当语句执行完后缓存会被清空。

Mybatis的一级缓存默认开启,且用户只能改变其级别,而不能进行关闭。所以我们重点看看Mybatis的二级缓存的使用:

二、Mybatis的缓存实现类

Mybatis的缓存基于JVM堆内存来实现的,即所有缓存对象都放在java对象中,并且通过Cache接口定义缓存对象的行为,Cache接口代码如下:

 Mybatis的缓存类使用装饰者模式,Cache接口只有一个基本的实现类,即PrepetualCache类,该类通过一个HasshMap存放缓存对象。需要注意的是,PrepetualCache类重写了Object类的equals方法(所以当两个缓存对象的id一样时(一般缓存对象的Id为mapper.xml中的命名空间名称,即全限定类名),则认为缓存对象相同)。

mybatis还对PerpetualCache类进行了增强,提供了一些缓存的装饰类,具体如下:

 这些装饰类相应的功能如下:

 另外缓存对象的创建是mybatis提供的CacheBuilder类通过生成器模式创建的,例如下面使用该类创建一个缓存对象:

三、一级缓存的实现原理

上面讲的缓存实现类,是mybatis一级缓存、二级缓存的基础,现在我们先来讲下一级缓存的实现。

Mybatis的一级缓存是SqlSession级别的缓存,在介绍核心组件的时候有提过SqlSession提供了面向用户的api,而真正执行sql的是Executor组件,Executor采用模板方法设计模式,BaseExecutor类用于处理一些通用的逻辑,其中一级缓存的逻辑就是在BaseExecutor类中完成的,

接下来我看看主要实现,一级缓存在BaseExecutor类中使用PerpetualCache实例实现的,在该类中维护了两个PerpetualCache属性,代码如下:

 其中localCache用来缓存Mybatis查询的结果,另一个用来缓存存储过程调用的结果。这两个属性在BaseExecutor构造方法中进行初始化的,代码如下:

Mybatis通过CacheKey对象来描述缓存的key值(即存进PerpetualCache实例的是一个key-value结构,可以为CacheKey,value为缓存对象),在执行查询操作时,先创建了Cachekey对象,如果两次查询操作的Cachekey对象相同,则认为这两次查询执行的是相同的SQL语句。CacheKey对象是通过BaseExecutor类的createKey方法创建的,代码如下:

 

 BaseExecutor类的query方法(即查询api)的具体实现:

可以看到,query方法中,先根据key去缓存中获取缓存对象,如果没有则调用queryFromDatabase方法从数据库中获取数据,然后再将数据写入缓存中。

需要注意的是,如果localCacheScope属性设置为statement时,每次查询操作完成后,都会调用clearLocalCache方法清空缓存,另外mybatis也会在每次执行更新操作前清空缓存,具体代码可以看BaseExecutor的update方法:

 可以看到,在调用doUpdate方法前都会先清空缓存。

注意:(这里后面验证一下)

四、Mybatis二级缓存实现原理

默认情况下二级缓存是关闭的,可通过摄者cacheEnabled参数值为true来开启二级缓存,前面说过Sqlsession将执行的逻辑委托给Executor组件完成,而Executor接口有几种不同的实现,分别为SimpleExecutor、BatchExecutor、ReuseExecutor,另外还有一个比较特殊的CachingExecutor,CachingExecutor采用了装饰器模式,在其他Executor的基础上增加了二级缓存功能。

        Executor实例创建是通过工厂模式创建,Configuration类提供一个工厂方法newExecutor方法用来创建返回一个Executor对象,我们可以看看这个方法的实现:

可以看到,Configuration类的newExecutor工厂方法根据defaultExecutorType参数知道的Executor类型创建对应的Executor实例。

如果cacheEnabled属性值为true(开启二级缓存),则使用CachingExecutor对普通的Executor对象进行装饰,CachingExecutor在普通的Executor的基础上增加了二级缓存,我们接下看看CachingExecutor的实现,下面先看看该类的属性信息:

 我们看看这个TransactionCacheManager(用于管理所以的二级缓存对象):

在TransactionalCacheManager类中,通过一个HashMap去维护二级缓存实例对应的 TransactionalCache对象,并提供获取缓存等方法。那么下面我们直接去看CachingExecutor的query实现方法:

 可以看到先调用了createCacheKey 创建缓存key,然后调用MapperStatement对象的getCache获取MapperStatement对象中维护的二级缓存对象(我们知道一个MapperStatement对应一个Mappper接口),然后从二级缓存对象中获取缓存结果,如果获取不到则调用Executor的query方法从数据库获取数据,在将数据添加到二级缓存,如果有更新操作则同一命名空间下的二级缓存会被清空,下面看下CachingExecutor的update方法:

上面我们说维护二级缓存的实例是从MappedStatement中获取的,那我们下面看看创建MapppedStatement是怎么去创建这些二级缓存实例的:

五、二级缓存集成redis

Redis实现Mybatis二级缓存_redis的二级缓存_悠然予夏的博客-CSDN博客

Mybatis的二级缓存、使用Redis做二级缓存

六、一级缓存与二级缓存的区别,以及二级缓存的弊端

  一级缓存的CacheKey是Mapper的命名空间+<select|update|insert|delete>的id组成的,且是基于SqlSession级别进行操作的(一般情况下,当我们使用Mybatis进行数据库的操作时候,会创建一个SqlSession来进行一次数据库的会话,会话结束则关闭SqlSession对象)

注意:两次查询须在同一个sqlsession中完成,否则将不会走mybatis的一级缓存。

在mybatis与spring进行整合开发时,事务控制在service中进行,重复调用两次servcie将不会走一级缓存,因为在第二次调用时session方法结束,SqlSession就关闭了。(同一个事务查询两次才会用到缓存)
(所以一般不用设置为Statement???)

而二级缓存则是基于Mapper级别进行的,即所有SqlSession的缓存进行共享(管理二级缓存额实例是存在MappedStatement的,而一个MappedStatement对应一个Mapper(即同一个命名空间对应一个二级缓存))

 

二级缓存是存在一个问题的,当对一个表的增删改查不在同一个namespace(即同一个接口中)时,会出现脏读现象,因为二级缓存是Mapper级别的(即一个Mapper接口层面),如果同一个表的修改在其他namespace(即其他Mapper)执行,此时第一个Mapper的二级缓存无法感知到第二个Mapper的二级缓存的改变,所以导致读到未刷新的数据。因此我们一般不建议使用二级缓存,如果需要使用二级缓存可以集成第三方缓存例如redis。

Mybatis二级缓存的缺陷_mybatis缓存的坏处_龙域、白泽的博客-CSDN博客

Mybatis一级缓存与二级缓存的区别你知道吗_mybatis的一级缓存和二级缓存的区别_Java小叮当的博客-CSDN博客

Mybatis 中的一级缓存与二级缓存_mybatis一级缓存和二级缓存_头真的好重好重Y的博客-CSDN博客

 

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

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

相关文章

主动配电网故障恢复的重构与孤岛划分统一模型研究【升级版本】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

CesiumForUnreal实现多边形裁剪3dTileset效果

文章目录 1.实现目标2.实现过程3.原理浅析4.参考资料1.实现目标 基于CesiumForUnreal插件的Cartographic Polygon Actor在Runtime运行时环境下实现对地形3DTileset的多边形裁剪效果,GIF动图如下: 2.实现过程 在Editor中的具体操作过程可以参考CesiumForUnreal官方裁剪地形的…

小巧型温湿度传感器

小巧型温湿度传感器是一种小巧的温湿度传感器&#xff0c;其作用是测量周围环境的温度和湿度&#xff0c;以及确定这些数据是否处于合适的范围内。这种传感器已经被广泛应用于医疗、工业、家居、冷链运输等领域&#xff0c;成为现代工业中不可或缺的一部分。小巧型温湿度传感器…

前置知识——Linux网络虚拟化

Linux网络虚拟化 信息是如何通过网络传输被另一个程序接收到的&#xff1f; 我们讨论的虚拟化网络是狭义的&#xff0c;它指容器间网络。 好了&#xff0c;下面我们就从 Linux 下网络通信的协议栈模型&#xff0c;以及程序如何干涉在协议栈中流动的信息来开始了解吧。 Linux…

全能PDF:Pdfium.Net SDK 2023-03-18 Crack

Pdfium.Net SDK 是领先的 .Net 库&#xff0c;用于生成、操作和查看可移植文档格式的文件。我们提供高级 c# / VB.Net API&#xff0c;用于在 WEB 服务器或任何其他服务器系统上动态创建 pdf&#xff0c;并在现有桌面或 WEB 应用程序中实现“另存为 PDF”功能。 入门&#xff1…

汽车网络管理的意义和分类

网络管理的意义&#xff1a; 1. 工作状态协同&#xff1a; 在任意多ECU节点网络工作时&#xff0c;对同一网络ECU的通信状态做统一的管理&#xff0c;保证各个ECU节点可以在条件满足的时候进入低功耗模式 2. 信息交互协同&#xff1a; 可以根据NM报文状态判定特定ECU的运行状态…

ESP32设备驱动-MPL3115A2压力传感器驱动

MPL3115A2压力传感器驱动 文章目录 MPL3115A2压力传感器驱动1、MPL3115A2介绍2、硬件准备3、软件准备4、驱动实现1、MPL3115A2介绍 MPL3115A2 是一款紧凑型压阻式绝对压力传感器,具有 I2C 数字接口。 MPL3115A2 具有 20 kPa 至 110 kPa 的宽工作范围,该范围涵盖了地球上的所…

CarSim仿真快速入门(二十四)-CarSimSimulink联合仿真中的输入和输出IO接口

导入和导出数组用于Simulink以外的外部仿真工具。同样的设置也用于LabVIEW、ASCET、FMI/FMU以及可能用MATLAB、Python和其他语言编写的自定义程序。 在所有这些情况下,I/O通道。导入和I/O通道。输出屏幕用于配置VS数学模型以满足外部仿真工具的通信要求。 I/O 通道:输出 输…

[攻城狮计划(三)] —— 看门狗定时器

&#x1f64c;秋名山码民的主页 &#x1f602;一个打过一年半的oier&#xff0c;写过一年多的Java&#xff0c;现在致力于学习iot应用的普通本科生 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f64f;作者水平有限&#xff0c;如发现…

双非二本如何入职腾讯?只需要做好这些准备就能进大厂?

每年的招聘旺季在“金三银四”和“金九银十”这2段时间&#xff0c;许多在春招中没有找到心仪大厂offer的测试小伙伴最近有私信我&#xff0c;想要了解如何在秋招中一举获得心仪大厂的青睐&#xff0c;那今天我就来和大家扒一扒那些大厂自动化测试面试题以及注意事项哦&#xf…

Python解题 - CSDN周赛第43期

感觉周赛越来越无趣了&#xff0c;基本都是考过的题目。上期周赛也是&#xff0c;4道题都曾考过&#xff0c;问哥也都写过题解&#xff0c;奖品也不吸引人&#xff0c;实在没什么好写了。 回想前段时间用力过猛&#xff0c;刷了C站大部分OJ题&#xff0c;以致于现在看到题目就直…

Elasticsearch:索引状态是红色还是黄色?为什么?

在我之前文章 “Elasticsearch&#xff1a;如何调试集群状态 - 定位错误信息” 中&#xff0c;我有详细介绍如何调试集群状态。在今天的文章中&#xff0c;我将详细介绍如何故障排除和修复索引状态。 Elasticsearch 是一个伟大而强大的系统&#xff0c;特别是创建一个可扩展性极…

MySQL函数、视图、存储过程及触发器

前言 MySQL在我们工作中都会用到&#xff0c;那么我们最常接触的就是增删改查&#xff0c;而对于增删改查来说&#xff0c;我们更多的是查询。但是面试中&#xff0c;面试官又不会问你什么查询是怎么写的&#xff0c;都是问一些索引啊&#xff0c;事务啊&#xff0c; 底层结构…

Hbase 介绍

Hbase 简介 Hbase 是一个开源的非关系型的分布式数据库&#xff0c;运用于HDFS文件系统之上&#xff0c;可以容错地存储海量稀疏的数据。Hbase是一个高可靠、高性能、面向列、可伸缩、实时读写的分布式数据库&#xff0c;主要用来存储非结构化和半结构化的松散数据 。 Hbase的…

ChatGPT中文在线官网-如何与chat GPT对话

怎么下载ChatGPT中文版 ChatGPT是一种基于Transformer架构的自然语言处理技术&#xff0c;其中包含了多个预训练的中文语言模型。这些中文ChatGPT模型大多数发布在Github上&#xff0c;可以通过Github的源码库来下载并使用&#xff0c;包括以下几种方式&#xff1a; 下载预训练…

高并发写场景:库存扣减

在设计商品的库存扣减逻辑时&#xff0c;可能一开始想到的(伪)代码是&#xff1a; <?php /*** 商品库存扣减** param int $skuId 商品ID* param int $num 库存扣减数量** return bool 扣减成功返回true&#xff0c;失败返回false*/ function stock_decr($skuId, $num) {…

Go是一门面向对象编程语言吗

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;tonybai|慕课网讲师 Go语言已经开源13年了&#xff0c;在近期TIOBE发布的2023年3月份的编程语言排行榜中&#xff0c;…

【hello Linux】Linux基本指令(下)

目录 1. more 指令&#xff1a;分批查看文件 1.1 more -n 文件名&#xff1a;查看文件前 n 行 1.2 more 文件名&#xff1a;屏幕输满 补充指令&#xff1a; 2. less 指令 2.1 less -N 文件名 2.2 /字符串&#xff1a;向下搜索“字符串”的功能 3. head 指令 3.1 head 文件名 3…

4.Java逻辑控制语句

Java逻辑控制语句 在实际生活中&#xff0c;我们的生活不是一成不变的&#xff0c;很多时候需要我们去选择&#xff0c;大到人生的十字路口&#xff0c;小到今天晚上吃什么&#xff0c;选择无处不在。小的选择决定了我们一件小事的走向&#xff0c;大的选择可能会改变我们人生…

基于多目标粒子群优化算法的计及光伏波动性的主动配电网有功无功协调优化(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…