Redis与Mybatis
作者在学习Redis整合时使用JDBC与Jedis,但是呢,现如今的环境下,Mybatis系列ORM框架是更受关注的方法,作者有一点点Mybatis基础,Mybatisplus几乎忘的差不多了,现对Redis整合Mybatis相关知识进行梳理,在进一步学习Mybatis系列知识后,再将具体代码进行补充测试。
结合 MyBatis 和 Redis 进行缓存可以通过 MyBatis 提供的缓存机制来实现。下面的例子将指导你如何使用 MyBatis-Redis-Cache 这个库进行整合。
基本步骤
添加依赖: 在你的 pom.xml 文件中添加 MyBatis 和 MyBatis-Redis-Cache 的依赖。
<dependencies><!-- 添加MyBatis依赖 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency><!-- 添加MyBatis-Redis-Cache依赖 --><dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-redis</artifactId><version>1.0.0</version></dependency>
</dependencies>
配置 Redis: 在 application.properties 或 application.yml 文件中配置 Redis 的相关信息。
# Redis 配置
spring.redis.host=你的Redis服务器地址
spring.redis.port=6379
配置 MyBatis: 在 MyBatis 的配置文件(例如 mybatis-config.xml)中开启缓存。
<settings><setting name="cacheEnabled" value="true"/>
</settings>
示例
假设你有一个 UserMapper 接口和相应的 UserMapper.xml 文件:
在 UserMapper.xml 文件中开启缓存:
<mapper namespace="com.example.mapper.UserMapper"><!-- 开启这个 namespace 的缓存 --><cache type="org.mybatis.caches.redis.RedisCache" /><select id="selectUserById" resultType="User">SELECT * FROM user WHERE id = #{id}</select>
</mapper>
在服务层使用 UserMapper:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public User getUserById(int id) {// 首次调用将查询数据库// 之后的调用将直接从 Redis 缓存中获取结果return userMapper.selectUserById(id);}
}
基础代码解释与自定义缓存类
在 MyBatis 的 Mapper XML 文件中使用
<cache type="com.example.cache.RedisCache" />标签和属性时,这是在告诉 MyBatis 使用默认的缓存实现。
机制
-
初始化时的操作:
- 当 MyBatis 初始化时,它会读取 Mapper XML 文件,并根据 XML 文件内容创建相应的 Mapper 对象。
- 当 MyBatis 遇到
<cache>标签时,它会尝试实例化指定类型(type属性)的缓存对象。 - 指定的缓存类(在本例中是
com.example.cache.RedisCache)会被实例化,并且在需要缓存操作时被 MyBatis 调用。
-
执行查询时的操作:
- 当执行查询(如
selectUserById)时,MyBatis 会首先检查缓存是否已经包含该查询的结果。因为在定义SQL语言之前,命名空间里还声明了<cache type="com.example.cache.RedisCache" />这种声明会让Mybatis做出对缓存的检查。 - 如果缓存中存在结果,MyBatis 就直接从缓存中返回结果,不再执行实际的 SQL 查询。
- 如果缓存中不存在结果,MyBatis 会执行 SQL 查询,并将查询结果存储在缓存中以供将来使用。
- 当执行查询(如
-
关闭操作:
- 当 MyBatis 会话结束时,所有的缓存资源应该被正确释放。
自定义缓存类
在使用 MyBatis 和 Redis 缓存时,如果你想要更多地控制 Redis 的详细操作,你可能需要自定义缓存处理逻辑。
其本质就是创建一个类,实现 MyBatis 的 Cache 接口。然后就把自定义类的名字换成之前的RedisCache就行,都是一样的配置。其自定义类代码如下所示:
import org.apache.ibatis.cache.Cache;
import redis.clients.jedis.Jedis;import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class MyRedisCache implements Cache {private final String id;private final Jedis redisClient = new Jedis("localhost", 6379);public MyRedisCache(String id) {this.id = id;}@Overridepublic String getId() {return this.id;}@Overridepublic void putObject(Object key, Object value) {redisClient.set(key.toString(), value.toString());}@Overridepublic Object getObject(Object key) {return redisClient.get(key.toString());}@Overridepublic Object removeObject(Object key) {return redisClient.del(key.toString());}@Overridepublic void clear() {redisClient.flushDB();}@Overridepublic int getSize() {return Integer.parseInt(redisClient.dbSize().toString());}@Overridepublic ReadWriteLock getReadWriteLock() {return new ReentrantReadWriteLock();}
}
在 MyBatis 的 Mapper XML 文件中使用自定义缓存类:
<mapper namespace="com.example.mapper.UserMapper"><!-- 使用自定义的缓存 --><cache type="com.example.cache.MyRedisCache" /><select id="selectUserById" resultType="User">SELECT * FROM user WHERE id = #{id}</select>
</mapper>
Cache接口实现
类定义中,读者可能会发现,咋多了这么多成员变量和方法啊?这其实是实现org.apache.ibatis.cache.Cache接口覆盖的成员和方法。
其中,有四个必须覆盖的方法:
String getId():返回缓存的标识符。每个缓存都必须有一个唯一的标识符。
void putObject(Object key, Object value):将查询结果存储在缓存中。
Object getObject(Object key):从缓存中获取由key指定的查询结果。
void clear():清除缓存中的所有项目。
三个可选覆盖的方法:
Object removeObject(Object key);int getSize();ReadWriteLock getReadWriteLock();
这些方法是可选的,意味着不一定非要覆盖它们。removeObject() 用于从缓存中移除对象,但并没有被 MyBatis 核心框架调用。同样,getSize() 和 getReadWriteLock() 也是可选的,并不是 MyBatis 核心部分的调用。这三个方法的实现依赖于你的实际缓存策略和需求。
Cache接口源码
为了更好地理解,作者查到16年某文章的cache源码。
package org.apache.ibatis.cache;import java.util.concurrent.locks.ReadWriteLock;/*** 缓存接口* 给缓存供应商的SPI(Service Provider Interface)* 一个Cache的实例将为名称空间被创建* Cache接口的实现类必须有一个具有String类型参数的构造方法,用于接收Cache对象的id,作为其唯一标识* * mybatis将以namespace作为id调用这个构造函数创建对象* * @author Administrator**/
public interface Cache {/*** 获取缓存对象的唯一标识* @return*/String getId();/*** 保存key/value到缓存对象中* key可以是任何对象,但一般是CacheKey对象* value是查询结果,为List类型* @param key* @param value*/void putObject(Object key, Object value);/*** 从缓存对象中获取key对应的value* @param key* @return*/Object getObject(Object key);/*** 可选的方法,没有被核心框架调用,移除key对应的value* @param key* @return*/Object removeObject(Object key);/*** 清空缓存*/void clear();/*** 获取缓存对象中存储的键/值对的数量* 可选的方法,没有被框架核心调用*/int getSize();/*** 获取读写锁* 可选的方法,从3.2.6起这个方法不再被框架核心调用* 任何需要的锁,都必须由缓存供应商提供* * @return A ReadWriteLock*/ReadWriteLock getReadWriteLock();}
是否可以新增方法?
可以在自定义缓存类中添加其他方法。
但是,这些额外的方法不会被 MyBatis 自动调用,它们只能在Override覆盖的方法内部调用。比如你想添加一个方法来计算 Redis 缓存的大小,你可以添加一个 size() 方法到你的自定义缓存类,并在 putObject 方法中调用它来更新缓存大小的信息。比如:
public class MyRedisCache implements Cache {// ...其他方法public int size() {// 实现计算 Redis 缓存大小的逻辑return 0;}@Overridepublic void putObject(Object key, Object value) {// 在存储对象之前或之后更新缓存大小信息// ...int currentSize = size();// ...}
}
注意,在MyBatis中:
会被自动调用的方法:
getId(): MyBatis会自动调用这个方法来获取缓存的唯一标识符。putObject(Object key, Object value): MyBatis会在将查询结果存入缓存时调用这个方法。getObject(Object key): MyBatis会在从缓存中获取对象时调用这个方法。clear(): 在执行更新、插入或删除操作时,MyBatis会调用这个方法来清空命名空间下的缓存。
不会被自动调用的方法:
removeObject(Object key): 这个方法在MyBatis核心框架中并不会被自动调用,但是你可以在自定义缓存实现中使用它。getSize(): 同样,这个方法也不会被MyBatis核心框架自动调用,除非你自己调用它。getReadWriteLock(): 从3.2.6版本开始,这个方法不再被框架核心调用。任何需要的锁,都必须由缓存提供商自行实现和管理。
总的来说,getId(), putObject(), getObject(), 和 clear() 这四个方法是在MyBatis操作过程中会被自动调用的,其他方法(removeObject(), getSize(), getReadWriteLock()和其他非Cache接口的方法)则不会,需要根据实际情况自行调用或实现。
示意代码
自动调用
考虑以下 Mapper XML 文件:
<mapper namespace="com.example.mapper.UserMapper"><cache type="com.example.cache.MyRedisCache" /><select id="selectUserById" resultType="User">SELECT * FROM user WHERE id = #{id}</select>
</mapper>
当执行 selectUserById 查询时:
- MyBatis 会调用
MyRedisCache类的getObject方法来尝试从 Redis 缓存中获取结果。 - 如果
getObject返回null(缓存未命中),MyBatis 将执行 SQL 查询并将结果通过putObject方法存储到 Redis 缓存中。 - 如果
getObject返回非null(缓存命中),MyBatis 将直接返回缓存的结果。
手动调用
既可以通过藏在自动调用的函数(不过这应该不属于手动调用),也可以通过获取 SqlSessionFactory 的 Configuration,然后获取特定的 Cache 对象来调用这个方法。不过貌似这种创建实例对象的方案不是很流行,具体等作者多学一点知识再说。
下面是一个例子:
SqlSessionFactory sqlSessionFactory = ... // 获取 SqlSessionFactory
Configuration configuration = sqlSessionFactory.getConfiguration();
Cache cache = configuration.getCache("com.example.cache.MyRedisCache"); // 使用你的 cache id
int size = cache.getSize();
System.out.println("Cache Size: " + size);
在这个例子中:
- 首先,获取了
SqlSessionFactory的实例。- 然后,从
SqlSessionFactory中获取了Configuration对象。- 接着,从
Configuration中通过 cache id 获取了Cache对象。- 最后,调用了
getSize()方法来获取缓存的大小。
相关文章:
Redis与Mybatis
作者在学习Redis整合时使用JDBC与Jedis,但是呢,现如今的环境下,Mybatis系列ORM框架是更受关注的方法,作者有一点点Mybatis基础,Mybatisplus几乎忘的差不多了,现对Redis整合Mybatis相关知识进行梳理…...
MySQL架构 InnoDB存储引擎
1. 什么是Mysql? 我们在开发的时候,我们都需要对业务数据进行存储,这个时候,你们就会用到MySQL、Oracal等数据库。 MySQL它是一个关系型数据库,这种关系型数据库就有Oracal、 MySQL,以及最近很火的PgSQL等。…...
K8S-CNI
CNI的设计思想即为:Kubernetes在启动Pod的pause容器之后,直接调用CNI网络插件,从而实现为Pod内部应用容器月在的Network Namespace配置符合预期的网络信息。 这里面需要特别关注两个方面:Container必须有自己的网络命名空间的环境,也就是end…...
Redis 集合类型(Set)和命令 (数据类型 四)
集合类型是一个无序、不重复的数据集合,它可以用于存储唯一的值,并提供了对集合进行交集、并集、差集等操作。 常用集合类型命令: 添加操作: sadd key member1 member2 …:向集合中添加一个或多个成员。 # 添加三个…...
thinkphp5 如何模拟在apifox里面 post数据接收
tp5里面控制器写的方法想直接apifox里面请求接受 必须带上这个参数 header里面 X-Requested-With:XMLHttpRequest...
建造者模式 创建型模式之三
想要搞清楚建造者模式,首先先要了解建造者模式种四个角色的定位 1.Product:表示被构造的复杂对象,就是我们要建造的东西,比如我们要做一个手机,手机就是product。 2.Builder:建造者,这里需要着…...
发布以太坊测试网络中的第一笔交易
1.安装以太坊钱包 要想发送发布以太坊测试网络中的第一笔交易,首先需要创建一个管理账户的钱包,这个钱包可以理解为管理私钥的容器,具体按照步骤为:打开Chrome浏览器应用商店搜索MetaMask,选择对应的钱包添加至Chrome…...
No module named ipykernel解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
Java 基于 SpringBoot 的校园疫情防控系统
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2.主要技术3 需求分析4系统设计4.1功能结构4.2 数据库设计4.2.1 数据库E/R图4.2.2 数据库表…...
windows的ui自动化测试相关
一个python第三方模块uiautomation github上也有源码,可以看下 uiautomation模块项目地址:https://github.com/yinkaisheng/Python-UIAutomation-for-Windows uiautomation模块项目地址...
Mybatis 二级缓存(使用Ehcache作为二级缓存)
上一篇我们介绍了mybatis中二级缓存的使用,本篇我们在此基础上介绍Mybatis中如何使用Ehcache作为二级缓存。 如果您对mybatis中二级缓存的使用不太了解,建议您先进行了解后再阅读本篇,可以参考: Mybatis 二级缓存https://blog.c…...
C语言 Cortex-A7核 IIC实验
iic.h #ifndef __IIC_H__ #define __IIC_H__ #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" /* 通过程序模拟实现I2C总线的时序和协议* GPIOF ---> AHB4* I2C1_SCL ---> PF14* I2C1_SDA ---> PF15** */#define SET_SDA_OUT do{…...
【每日一题】2769. 找出最大的可达成数字
2769. 找出最大的可达成数字 - 力扣(LeetCode) 给你两个整数 num 和 t 。 如果整数 x 可以在执行下述操作不超过 t 次的情况下变为与 num 相等,则称其为 可达成数字 : 每次操作将 x 的值增加或减少 1 ,同时可以选择将 …...
开源电子合同签署平台小程序源码 在线签署电子合同小程序源码 合同在线签署源码
聚合市场上各类电子合同解决方案商,你无需一个一个的对接电子合同厂商, 费时,费力,因为这个工作我们已经做了适配,你只需要一个接口就能使用我们的所有服务商, 同时你还可以享受我们的接口渠道价格。 Mini-…...
36 二叉树中序遍历
二叉树中序遍历 题解1 递归题解2 迭代 给定一个二叉树的根节点 root ,返回它的 中序 遍历 。 提示: 树中节点数目在范围 [0, 100] 内-100 < Node.val < 100 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 题解1 递归…...
广州华锐互动:VR结绳逃生训练模拟真实火灾场景,增强训练沉浸感
随着科技的发展,虚拟现实(VR)技术已被广泛应用到各个领域,其中包括消防训练。VR消防结绳训练是一种创新的消防训练方式,它通过虚拟现实技术模拟真实的灭火场景,使消防人员能够在无风险的环境中进行高强度的…...
Flink安装及简单使用
目录 转载处(个人用最新1.17.1测试) 依赖环境 安装包下载地址 Flink本地模式搭建 安装 启动集群 查看WebUI 停止集群 Flink Standalone搭建 安装 修改flink-conf.yaml配置文件 修改workers文件 复制Flink安装文件到其他服务器 启动集群 查…...
QT信号槽
目录 信号槽的概念 按钮的常用信号 自定义槽函数 自定义信号函数 自定义槽和信号注意的事项 信号与槽的拓展 lambda表达式 信号槽的概念 信号槽是Qt框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,…...
Spring Boot 技术架构图(InsCode AI 创作助手辅助)
Spring Boot 技术架构是一种用于构建现代应用程序的框架,它可以与各种前端、代理、网关、业务服务、中间件、存储、持续集成和容器服务集成在一起,以创建功能强大的应用程序。 源文件下载链接!!!!ÿ…...
python使用mitmproxy和mitmdump抓包在手机上抓包(三)
现在手机的使用率远超过电脑,所以这篇记录用mitmproxy抓手机包,实现手机流量监控。 环境:win10 64位,Python 3.10.4,雷电模拟器4.0.78,android版本7.1.2(设置-拉至最底部-关于平板电脑…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...
CMS内容管理系统的设计与实现:多站点模式的实现
在一套内容管理系统中,其实有很多站点,比如企业门户网站,产品手册,知识帮助手册等,因此会需要多个站点,甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...
Cursor AI 账号纯净度维护与高效注册指南
Cursor AI 账号纯净度维护与高效注册指南:解决限制问题的实战方案 风车无限免费邮箱系统网页端使用说明|快速获取邮箱|cursor|windsurf|augment 问题背景 在成功解决 Cursor 环境配置问题后,许多开发者仍面临账号纯净度不足导致的限制问题。无论使用 16…...
