七、Redis 缓存 —— 超详细操作演示!

七、Redis 缓存 —— 超详细操作演示!

    • 七、Redis 缓存
      • 7.1 Jedis 客户端
          • 7.1.1 Jedis 简介
          • 7.1.2 创建工程
          • 7.1.3 使用 Jedis 实例
          • 7.1.4 使用 JedisPool
          • 7.1.5 使用 JedisPooled
          • 7.1.6 连接 Sentinel 高可用集群
          • 7.1.7 连接分布式系统
          • 7.1.8 操作事务
      • 7.2 金融产品交易平台
      • 7.3 高并发问题
    • 八、Lua脚本详解
      • 8.1 Lua 简介
      • 8.2 Linux 系统的Lua
      • 8.3 Win 系统的Lua
      • 8.4 Lua 脚本基础
      • 8.5 Lua 语法进阶
    • 九、分布式锁
      • 9.1 分布式锁的工作原理
      • 9.2 问题引入
      • 9.3 setnx 实现方式
      • 9.4 为锁添加过期时间
      • 9.5 为锁添加标识
      • 9.6 添加 Lua 脚本
      • 9.7 Redisson 可重入锁
      • 9.8 Redisson 红锁
      • 9.9 分段锁
      • 9.10 Redisson 详解

数据库系列文章:

关系型数据库:

  • MySQL —— 基础语法大全
  • MySQL —— 进阶


非关系型数据库:

  • 一、Redis 的安装与配置
  • 二、Redis 基本命令(上)
  • 三、Redis 基本命令(下)
  • 四、Redis 持久化
  • 五、Redis 主从集群

七、Redis 缓存

7.1 Jedis 客户端

7.1.1 Jedis 简介

    Jedis 是一个 基于 java 的 Redis 客户端连接工具 ,旨在提升性能易用性 。 其 github 上的官网地址为: https://github.com/redis/jedis 。

7.1.2 创建工程

    首先创建一个普通的 Maven 工程 01-jedis ,然后在 POM 文件中添加 Jedis 与 Junit 依赖。

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> 
</properties> <dependencies> <!--jedis依赖--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> 
</dependencies>
7.1.3 使用 Jedis 实例

    Jedis 基本使用十分简单, 其提供了非常丰富的操作 Redis 的方法,而这些方法名几乎与 Redis 命令相同。 在每次使用时直接创建 Jedis 实例即可。在 Jedis 实例 创建好之后, Jedis 底层实际会创建一个到指定 Redis 服务器Socket 连接 。所以 ,为 了节省系统资源网络带宽 在每次使用完 Jedis 实例 之后,需要立即调用 close() 方法将 连接关闭。

    首先,需要在工程的 src/test/java 下创建测试类 JedisTest

⭐️(1) value 为 String 的测试

@Test
public void test01() {Jedis jedis = new Jedis("redis", 6379);jedis.set("name", "张三");jedis.mset("age", "23", "depart", "市场部");System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));System.out.println("depart = " + jedis.get("depart"));jedis.close();
}

在这里插入图片描述
在这里插入图片描述

⭐️(2) value 为 Hash 的测试

@Test
public void test02() {Jedis jedis = new Jedis("redis", 6379);jedis.hset("emp", "name", "Tom");Map<String, String> map = new HashMap<>();map.put("age", "24");map.put("depart", "行政部");jedis.hset("emp", map);System.out.println("emp.name = " + jedis.hget("emp", "name"));List<String> emp = jedis.hmget("emp", "name", "age", "depart");System.out.println("emp = " + emp);jedis.close();
}

在这里插入图片描述

⭐️(3) value 为 List 的测试

// value为List的情况
@Test
public void test03() {Jedis jedis = new Jedis("redis", 6379);jedis.rpush("cities", "北京", "上海", "广州");List<String> cities = jedis.lrange("cities", 0, -1);System.out.println("cities = " + cities);jedis.close();
}

在这里插入图片描述

⭐️(4) value 为 Set 的测试

// value为Set的情况
@Test
public void test04() {Jedis jedis = new Jedis("redis", 6379);jedis.sadd("courses", "Redis", "RocketMQ", "Zookeeper", "Kafka");Set<String> courses = jedis.smembers("courses");System.out.println("courese = " + courses);jedis.close();
}

在这里插入图片描述

⭐️(5) value 为 Zset 的测试

// value为ZSet的情况
@Test
public void test05() {Jedis jedis = new Jedis("redis", 6379);jedis.zadd("sales", 50, "Benz");jedis.zadd("sales", 40, "BMW");jedis.zadd("sales", 30, "Audi");jedis.zadd("sales", 80, "Tesla");jedis.zadd("sales", 120, "BYD");List<String> top3 = jedis.zrevrange("sales", 0, 2);System.out.println("top3 = " + top3);List<Tuple> sales = jedis.zrevrangeWithScores("sales", 0, -1);for (Tuple sale : sales) {System.out.println(sale.getScore() + ":" + sale.getElement());}jedis.close();
}

在这里插入图片描述

7.1.4 使用 JedisPool

    如果应用非常 频繁地 创建和销毁 Jedis 实例 虽然节省了系统资源与网络带宽,但会大大降低系统性能。 因为 创建和销毁 Socket 连接 是比较耗时的 。 此时可以使用 Jedis 连接池 来解决该问题。

    使用 JedisPool 与使用 Jedis 实例的区别是, JedisPool全局性的整个类只需创建一次即可,然后每次需要操作 Redis 时,只需从 JedisPool 中拿出一个 Jedis 实例 直接使用即可。使用完毕后,无需释放 Jedis 实例,只需 返回 JedisPool 即可。

public class JedisPoolTest{private JedisPool jedisPool = new JedisPool("redis", 6379);// value为String的情况@Testpublic void test01() {try (Jedis jedis = jedisPool.getResource()) {jedis.set("name", "张三");jedis.mset("age", "23", "depart", "行政部");System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));System.out.println("depart = " + jedis.get("depart"));}}
}
7.1.5 使用 JedisPooled

    对于每次对 Redis 的操作都需要使用 try-with-resource 块是比较麻烦的,而使用 JedisPooled 则无需再使用该结构来自动释放资源了。

public class JedisPooledTest {private JedisPooled jedisPooled = new JedisPooled("redis", 6379);// vaLue为String的情况@Testpublic void test01() {jedisPooled.set("name", "张三");jedisPooled.mset("age", "23", "depart", "行政部");System.out.println("name = " + jedisPooled.get("name"));System,out.println("age = " + jedisPooled.get("age"));System.out.println("depart = " + jedisPooled.get("depart"));}
}
7.1.6 连接 Sentinel 高可用集群

    对于 Sentinel 高可用集群的连接,直接使用 JedisSentinelPool 即可。在该客户端只需注册所有 Sentinel 节点 及其监控的 Master 的名称即可,无需出现 master -slave 的任何地址信息。其采用的也是 JedisPool ,使用完毕的 Jedis 也需要通过 close() 方法将其返回给 连接池

public class JedisSentinelPoolTest {private JedisSentinelPool jedisPool;{HashSet<String> sentinels = new HashSet<>();sentinels.add("redis:26380");sentinels.add("redis:26381");sentinels.add("redis:26382");jedisPool = new JedisSentinelPool("mymaster", sentinels);}// vaLue为String的情况@Testpublic void test01() {try (Jedis jedis = jedisPool.getResource()) {jedis.set("name", "张三");jedis.mset("age", "23", "depart", "行政部");System.out.println("name = " + jedis.get("name"));System.out.println("age = " + jedis.get("age"));System.out.println("depart = " + jedis.get("depart"));}}
}
7.1.7 连接分布式系统

    对于 Redis 的分布式系统的连接,直接使用 JedisCluster 即可。其底层采用的也是 Jedis连接池技术。每次使用完毕后,无需显式关闭,其会自动关闭

    对于 JedisCluster 常用的 构造器 有两个。

  • 一个是 只需一个集群节点 的构造器,这个节点可以是集群中的任意节点,只要连接上了该节点,就连接上了整个集群。但该构造器存在一个风险:其指定的这个节点在连接之前恰好宕机,那么该客户端将无法连接上集群。
  • 所以,推荐使用第二个构造器,即将集群中所有节点全部罗列出来。这样就会避免这种风险了 。
public class JedisClusterTest{private JedisCluster jedisCluster;{// 连接CLuster中的任意主机// HostAndPort node = new HostAndPort("redis", 6380);// jedisCluster = new JedisCluster(node);//连接整个CLusterHashSet<HostAndPort> nodes = new HashSet<>();nodes.add(new HostAndPort("redis", 6380));nodes.add(new HostAndPort("redis", 6381));nodes.add(new HostAndPort("redis", 6382));nodes.add(new HostAndPort("redis", 6383));nodes.add(new HostAndPort("redis", 6384));nodes.add(new HostAndPort("redis", 6385));jedisCluster = new JedisCluster(nodes);}// value为String的情况@Testpublic void test01() {jedisCluster,set("name", "张三");// 会出现跨槽,报错// jedisClustermset("age", "23", "depart","行政部");System.out.println("name = " + jedisCluster.get("name"));}
}
7.1.8 操作事务

    对于 Redis 事务 的操作, Jedis 提供了 multi()watch() 、 unwatch() 方法来对应 Redis 中的 multiwatchunwatch 命令。 Jedis 的 multi() 方法返回一个 Transaction 对象,其 exec()discard() 方法用于 执行和取消事务的执行

⭐️(1) 抛出 Java 异常

public class JedisTxTest {
private JedisPool jedisPool = new JedisPool("redis", 6379);@Test
public void test01() {try (Jedis jedis = jedisPool.getResource()) {jedis.set("name", "张三");jedis.set("age", "23");Transaction multi = jedis.multi();try {multi.set("name", "李四");// 构造一个Java异常int i = 3/0;multi.set("age", "24");multi.exec();} catch (Exception e) {// 一旦发生异常,全部回滚multi.discard();} finally {System.out.println(jedis.get("name")); // 张三System.out.println(jedis.get("age")); // 23}}
}

    其输出结果为全部回滚的结果

⭐️(2) 让 Redis 异常

@Test
public void test02() {try (Jedis jedis = jedisPool.getResource()) {jedis.set("name", "张三");jedis.set("age", "23");Transaction multi = jedis.multi();try {multi.set("name", "李四");// 构造一个Redis异常,不会影响后面的执行multi.incr("name");multi.set("age", "24");multi.exec();} catch (Exception e) {// Redis异常不会被Java代码捕获到multi.discard();} finally {System.out.println(jedis.get("name")); // 李四System.out.println(jedis.get("age")); // 24}}
}

    其输出结果为修改过的值。说明 Redis 运行时 抛出的异常不会被 Java 代码捕获到,其不会影响 Java 代码的执行。

⭐️(3) watch()

@Test
public void test03() {try (Jedis jedis = jedisPool.getResource()) {jedis.set("age", "23");System.out.println("增一前的age值:" + jedis.get("age")); // 23jedis.watch("age");Transaction multi = jedis.multi();multi.incr("age");multi.exec();System.out.println("增一后的age值:" + jedis.get("age"));}
}

7.2 金融产品交易平台

7.2.1 Spring Boot 整合 Redis

7.2.2 Redis 操作模板

    Spring Boot 中可以直接使用 Jedis 实现对 Redis 的操作,但一般不这样用,而是使用 Redis 操作模板 RedisTemplate 类的实例来操作 Redis 。

    RedisTemplate 类是一个对 Redis 进行操作的模板类。该模板类中具有很多方法,这些方法很多与 Redis 操作命令同名或类似。例如, delete()keys()scan(),还有事务相关的 multi()exec()discard()watch() 等。当然还有获取对各种 Value 类型进行操作的操作实例的两类方法 boundXxxOps(k)opsForXxx()

7.2.3 需求

    下面通过一个例子来说明 Spring Boot 是如何与 Redis 进行整合的。

    对于一个资深成熟的金融产品交易平台,其用户端首页一般会展示其最新金融产品列表同时还为用户提供了产品查询功能。另外,为了显示平台的实力与信誉,在平台首页非常显眼的位置还会展示平台已完成的总交易额注册用户数量。对于管理端,管理员可通过管理页面修改产品上架新产品下架老产品

    为了方便了解 Redis 与 Spring Boot 的整合流程,这里对系统进行了简化:用户端首页仅提供根据金融产品名称的查询,显眼位置仅展示交易总额。管理端仅实现上架新产品功能。

7.2.4 创建 SSM 工程

⭐️(1) 创建工程

    定义一个 Spring Boot 工程,并命名为 ssm 。

⭐️(2) 定义 pom 文件

    在 pom 文件中需要导入 MySQL 驱动、 Druid 等大量依赖。 POM 文件中的重要内容如下:

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.12</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/webapp</directory><targetPath>META-INF/resources</targetPath><includes><include>**/*.*</include></includes></resource></resources></build>

⭐️(3) 修改主配置文件

    在主配置文件中配置 MyBatisSpring日志等配置:

⭐️(4) 实体类 Product

平台交易总额,即“产品募集结束日期”小于“当前查询日期”的“产品募集总额”之和。

⭐️(5) 创建数据库表

    在 test 数据库中创建一个名称为 product 的表。创建的 sql 文件如下,直接运行该文件即可。

⭐️(6) 定义 index.jsp

    在 src/main 下创建 webap 目录,用于存放 jsp 文件。这就是一个普通的目录,无需执行 Mark Directory As 。在 webapp 目录中创建一个 index.jsp 文件。

⭐️(7) 定义 manager.jsp

    在 webapp 目录下再创建一个 jsp 子目录,在其中定义 manager.jsp

⭐️(8) 定义 result.jsp

    在 webapp/jsp 中定义 result.jsp

⭐️(9) ProductController 类

A、 indexHandle()

B、 registerHandle()

C、 listHandle()

⭐️(10) ProductService 接口

⭐️(11) ProductServiceImpl 类

A、 saveProduct()

B、 三个 find 方法

⭐️(12) ProductDao 接口

⭐️(13) 映射文件

⭐️(14) Application 启动类

7.2.5 创建 SSRM 工程

7.3 高并发问题

八、Lua脚本详解

8.1 Lua 简介

8.2 Linux 系统的Lua

8.3 Win 系统的Lua

8.4 Lua 脚本基础

8.5 Lua 语法进阶

九、分布式锁

9.1 分布式锁的工作原理

9.2 问题引入

9.3 setnx 实现方式

9.4 为锁添加过期时间

9.5 为锁添加标识

9.6 添加 Lua 脚本

9.7 Redisson 可重入锁

9.8 Redisson 红锁

9.9 分段锁

9.10 Redisson 详解

🚀🚀🚀 Redis 快速食用:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------->


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

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

相关文章

2022.07.25 C++下使用opencv部署yolov7模型(五)

0.写在最前 此篇文字针对yolov7-1.0版本。 最近粗略的看了一遍yolov7的论文&#xff0c;关于yolov7和其他yolo系列的对比&#xff0c;咱就不多说了&#xff0c;大佬们的文章很多很详细。关于opencv部署方面&#xff0c;其实yolov7和yolov5的初期版本&#xff08;5.0以前的版本…

多维时序 | MATLAB实现SSA-CNN-GRU-SAM-Attention麻雀算法优化卷积网络结合门控循环单元网络融合空间注意力机制多变量时间序列预测

多维时序 | MATLAB实现SSA-CNN-GRU-SAM-Attention麻雀算法优化卷积网络结合门控循环单元网络融合空间注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实现SSA-CNN-GRU-SAM-Attention麻雀算法优化卷积网络结合门控循环单元网络融合空间注意力机制多变量时间序列预测预测效…

费曼学习法应用:谈自私和教育的引导

今天这个还是来源于我和九迁的对话&#xff0c;起因是中午吃饭的时候&#xff0c;九迁在学校与班主任老师和数学老师对话中带来的思考。 先听音频&#xff1a; 对话内容&#xff08;以下内容可以边听边看&#xff0c;属于语音转换过来的文字&#xff0c;最后有个总结&#xff0…

【Java进阶篇】SimpleDateFormat是线程安全的吗? 使用时应该注意什么?

SimpleDateFormat是线程安全的吗?使用时应该注意什么? ✔️ 典型解析✔️拓展知识仓✔️SimpleDateFormat用法✔️日期和时间模式表达方法✔️输出不同时区的时间✔️SimpleDateFormat线程安全性✔️问题重现✔️线程不安全原因✔️如何解决✔️使用局部变量✔️加同步锁✔️…

HTML标签基础入门

HTML 基本语法概述标签关系HTML基础结构HTML常用标签标题标签示例 段落和换行标签示例 文本格式化标签示例 div和span标签示例 图像标签和路径示例 超链接标签示例 注释 ctrl/特殊字符示例 表格标签 表头单元格标签表格属性示例 合并单元格示例 列表标签无序列表有序列表自定义…

GRNdb:解码不同人类和小鼠条件下的基因调控网络

GRNdb&#xff1a;解码不同人类和小鼠条件下的基因调控网络 摘要introduction数据收集和处理Single-cell and bulk RNA-seq data collection and processing 单细胞和bulk RNA-seq 数据收集和处理Cell cluster identification for scRNA-seq datasets &#xff08;scRNA-seq 数…

Docker之镜像上传和下载

目录 1.镜像上传 1) 先上百度搜索阿里云 点击以下图片网站 2) 进行登录/注册 3) 使用支付宝...登录 4) 登录后会跳转到首页->点击控制台 5) 点击左上角的三横杠 6) 搜索容器镜像关键词->点击箭头所指 ​ 编辑 7) 进入之后点击实例列表 8) 点击个人实例进入我们的一个…

软件测试/测试开发丨Linux进阶命令(curl、jq)

1、 curl 接口请求 curl是一个发起请求数据给服务器的工具curl支持的协议FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3、SMTP和RTSPcurl是一个非交互的工具 2、 curl 发起 get 请求 -G&#xff1a;使用get请求-d&#xf…

我在Vscode学OpenCV 图像处理四(轮廓查找 cv2.findContours() cv2.drawContours())-- 待补充

图像处理四&#xff08;轮廓查找&#xff09; 一、前言1.1 边缘检测和轮廓查找的区别是什么1.1.1 边缘检测&#xff1a;1.1.2 轮廓查找&#xff1a; 1.2 边缘检测和轮廓查找在图像处理中的关系和流程 二、查找并绘制轮廓2.1 cv2.findContours()&#xff1a;2.1.1 详细介绍&…

Unity Shader UVLightReveal (紫外线显示,验钞效果)

Unity Shader UVLightReveal &#xff08;紫外线显示&#xff0c;验钞效果&#xff09; UVLight Reveal 实现验钞机的效果实现方案操作实现1.Light2.将另一个图形加入3.加上图形效果4.加上灯光的颜色自定义判定 源码 UVLight Reveal 实现验钞机的效果 大家应该都有见过验钞机验…

ARM12.25

串口发送控制命令&#xff0c;实现一些外设LED 风扇 马达 运转 下实现灯亮 uart4.h #ifndef __UART4_H__ #define __UART4_H__ #include"stm32mp1xx_rcc.h" #include"stm32mp1xx_gpio.h" #include"stm32mp1xx_uart.h" void uart4_config(); v…

elasticsearch列一:索引模板的使用

概述 近期一直在负责es这块&#xff0c;就想着和大家分享一些使用经验&#xff0c;我们从存储、查询、优化、备份、运维等几个方面来做分享。今天咱们先看下如何更加合理的存储数据。 初见索引模板 记得刚接触es还是18年那会&#xff0c;项目上线后因一些原因导致日志这部分的…