Redisson 总结
1. 基础使用
1.1 引入依赖
<dependencies><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId></dependency>
</dependencies>
包含的依赖如下

1.2 配置文件
其实默认主机就是 127.0.0.1,默认端口是 6379,一致的话可以不用配置
spring:data:redis:host: 127.0.0.1password: redis
1.3 测试类
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RBucket<String> bucket = redissonClient.getBucket("test");bucket.set("hello");}@GetMapping("/get")public String get() {RBucket<String> bucket = redissonClient.getBucket("test");return bucket.get();}
}
1.4 测试
访问 /test 接口,利用 Redis 管理工具可以看到数据已经添加了进来

在访问 /get 接口,成功获取到数据

2. 设置序列化
上面可以看到在 Redis 管理工具中查看数据是一串字符,并不直观,可以自定义数据序列化
2.1 配置类
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();// 单机模式SingleServerConfig singleServerConfig = config.useSingleServer();singleServerConfig.setAddress("redis://127.0.0.1:6379");singleServerConfig.setPassword("redis");// JSON序列化config.setCodec(new JsonJacksonCodec());return Redisson.create(config);}
}
这里已经配置了主机等相关信息,因此配置文件里的配置可以去除,或者这里直接取配置文件的值,具体根据情况选择,其他的序列化类如下
| 编码类名称 | 说明 |
|---|---|
| org.redisson.codec.JsonJacksonCodec | Jackson JSON 编码 |
| org.redisson.codec.AvroJacksonCodec | Avro 一种二进制的 JSON 编码 |
| org.redisson.codec.SmileJacksonCodec | Smile一种 二进制的 JSON 编码 |
| org.redisson.codec.CborJacksonCodec | CBOR 一种二进制的 JSON 编码 |
| org.redisson.codec.MsgPackJacksonCodec | MsgPack 一种 二进制的 JSON 编码 |
| org.redisson.codec.IonJacksonCodec | Amazon Ion 亚马逊的 Ion 编码,格式与 JSON 类似 |
| org.redisson.codec.KryoCodec | Kryo 二进制对象序列化编码 |
| org.redisson.codec.SerializationCodec | JDK 序列化编码 |
| org.redisson.codec.FstCodec | FST 10 倍于 JDK 序列化性能而且 100% 兼容的编码 |
| org.redisson.codec.LZ4Codec | LZ4 压缩型序列化对象编码 |
| org.redisson.codec.SnappyCodec | Snappy 另一个压缩型序列化对象编码 |
| org.redisson.client.codec.JsonJacksonMapCodec | 基于 Jackson 的映射类使用的编码,可用于避免序列化类的信息,以及用于解决使用byte[] 遇到的问题 |
| org.redisson.client.codec.StringCodec | 纯字符串编码(无转换) |
| org.redisson.client.codec.LongCodec | 纯整长型数字编码(无转换) |
| org.redisson.client.codec.ByteArrayCodec | 字节数组编码 |
| org.redisson.codec.CompositeCodec | 用来组合多种不同编码在一起 |
2.2 测试
访问 /test 接口,再查看数据可以看到已经序列化成 JSON 格式

3. 基础数据结构使用
3.1 String
其实上面的示例用的就是字符串操作,通过 RBucket 对象来操作字符串数据结构
创建一个实体类
import lombok.Builder;
import lombok.Data;import java.io.Serial;
import java.io.Serializable;@Data
@Builder
public class Article implements Serializable {@Serialprivate static final long serialVersionUID = -8862397425409851538L;private String title;private String content;
}
存储对象,简单示例如下:
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RBucket<Object> bucket = redissonClient.getBucket("test");bucket.set(Article.builder().title("demo").content("test redisson").build());}
}
数据如下:

3.2 Hash
通过 RMap 对象来操作哈希数据结构,简单示例如下:
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RMap<String, Article> rMap = redissonClient.getMap("test");rMap.put("k1", Article.builder().title("demo").content("test redisson").build());}
}
数据如下:

3.3 List
3.3.1 无序
通过 RList 对象来操作列表数据结构,简单示例如下:
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RList<Article> rList = redissonClient.getList("test");rList.add(Article.builder().title("demo").content("test redisson").build());rList.add(Article.builder().title("demo").content("test redisson").build());}
}
数据如下:

3.3.2 有序
通过 RSortedSet 对象来操作有序集合数据结构
改造一下实体类,实现 Comparable 接口
import lombok.Data;import java.io.Serial;
import java.io.Serializable;@Data
public class Article implements Serializable, Comparable<Article> {@Serialprivate static final long serialVersionUID = -8862397425409851538L;private Long id;private String title;private String content;@Overridepublic int compareTo(Article article) {return this.getId().compareTo(article.getId());}
}
简单示例如下:
import org.redisson.api.RSortedSet;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RSortedSet<Article> rSortedSet = redissonClient.getSortedSet("test");Article article1 = new Article();article1.setId(22L);article1.setTitle("demo");article1.setContent("test redisson");rSortedSet.add(article1);Article article2 = new Article();article2.setId(11L);article2.setTitle("demo");article2.setContent("test redisson");rSortedSet.add(article2);}
}
数据如下,可以看到数据根据 id 排序

3.4 Set
通过 RSet 对象来操作集合数据结构,简单示例如下:
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RSet<Article> rSet = redissonClient.getSet("test");rSet.add(Article.builder().title("demo").content("test redisson").build());rSet.add(Article.builder().title("demo").content("test redisson").build());}
}
数据如下,可以看到重复数据被去除了

3.5 Zset
通过 RScoredSortedSet 来操作带分数的有序集合数据结构,简单示例如下:
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet("test");rScoredSortedSet.add(600.1, "test1");rScoredSortedSet.add(500.3, "test2");rScoredSortedSet.add(900.3, "test3");rScoredSortedSet.add(200.9, "test1");}
}
数据如下,可以看到根据分数来排序,并且重复数据被排除了

4. 布隆过滤器
可以用于检索一个元素是否在一个集合中
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.time.Duration;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RBloomFilter<String> rBloomFilter = redissonClient.getBloomFilter("test");// 初始化预期插入的数据量为10000和期望误差率为0.01rBloomFilter.tryInit(10000, 0.01);// 插入部分数据rBloomFilter.add("100");rBloomFilter.add("200");rBloomFilter.add("300");// 设置过期时间rBloomFilter.expire(Duration.ofSeconds(30));// 判断是否存在System.out.println(rBloomFilter.contains("300")); // trueSystem.out.println(rBloomFilter.contains("200")); // trueSystem.out.println(rBloomFilter.contains("999")); // false}
}
5. 分布式自增 ID
参考代码如下:
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RAtomicLong rAtomicLong = redissonClient.getAtomicLong("test");System.out.println(rAtomicLong.incrementAndGet());}
}
6. 分布式锁
6.1 未加锁情况
模拟一个库存扣减操作
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RBucket<Integer> bucket = redissonClient.getBucket("num");Integer num = bucket.get();if (num > 0) {System.out.println("扣减库存, 当前库存: " + --num);bucket.set(num);} else {System.out.println("库存不足");}}
}
使用 Jemter 模拟并发场景


点击运行后可以看到明显出现了并发问题

6.2 加锁情况
修改下库存扣减代码
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RLock rLock = redissonClient.getLock("test");try {rLock.lock();RBucket<Integer> bucket = redissonClient.getBucket("num");Integer num = bucket.get();if (num > 0) {System.out.println("扣减库存, 当前库存: " + --num);bucket.set(num);} else {System.out.println("库存不足");}} finally {rLock.unlock();}}
}
再次模拟并发请求,可以看到问题已经解决

6.3 加锁操作耗时长
当加锁操作耗时较长时,如果多个请求进来,其他的请求会一直堵塞,可以使用 tryLock 来尝试获取锁,获取不到先返回响应
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final RedissonClient redissonClient;@Autowiredpublic DemoController(RedissonClient redissonClient) {this.redissonClient = redissonClient;}@GetMapping("/test")public void test() {RLock rLock = redissonClient.getLock("test");try {if (rLock.tryLock()) {RBucket<Integer> bucket = redissonClient.getBucket("num");Integer num = bucket.get();Thread.sleep(5000);if (num > 0) {System.out.println("扣减库存, 当前库存: " + --num);bucket.set(num);} else {System.out.println("库存不足");}} else {System.out.println("请稍后再试");}} catch (InterruptedException e) {System.out.println(e.getMessage());Thread.currentThread().interrupt();} finally {// 是否是锁定状态且是当前执行线程的锁if (rLock.isLocked() && rLock.isHeldByCurrentThread()) {rLock.unlock();}}}
}
模拟并发请求,这里将时间设置长一点,可以看到获取到锁的请求则去进行库存扣减,获取不到先返回响应

相关文章:
Redisson 总结
1. 基础使用 1.1 引入依赖 <dependencies><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId></dependency> </dependencies>包含的依赖如下 1.2 配置文件 其实默认主机就…...
EfficientFormer实战:使用EfficientFormerV2实现图像分类任务(一)
摘要 EfficientFormerV2是一种通过重新思考ViT设计选择和引入细粒度联合搜索策略而开发出的新型移动视觉骨干网络。它结合了卷积和变换器的优势,通过一系列高效的设计改进和搜索方法,实现了在移动设备上既轻又快且保持高性能的目标。这一成果为在资源受…...
文心智能体搭建步骤
通过使用文心智能体平台来创建智能体的过程。这种方法可以让没有编程经验的人也能快速构建智能体,降低了技 术门槛。以下是一些建议和心得: 1.选择合适的平台:文心智能体平台是一个优秀的选择,它提供了零代码和低代码的开发环境,极大地降低了…...
PHP安全
PHP伪协议: 一.【file://协议】 PHP.ini: file:// 协议在双off的情况下也可以正常使用; allow_url_fopen :off/on allow_url_include:off/on file:// 用于访问本地文件系统,在CTF中通常用来读取本地文…...
c++278函数指针
#define _CRT_SECURE_NO_WARNINGS #include<stdlib.h> #include<string.h> #include<stdio.h>//数组类型基本语法知识梳理 //定义一个数组类型 //int a[10];//定义一个指针数组类型//定义一个指向数组类型的指针 数组类型的指针void main() {int a[10];//a代…...
sklearn特征选取之SelectFromModel
sklearn.feature_selection.SelectFromModel 是一种基于模型的重要性权重进行特征选择的工具,允许我们根据学习器的权重或特征重要性自动选择特征。它通过从模型中提取特征的重要性来选择特征,常用于与那些具有 coef_ 或 feature_importances_ 属性的模型…...
vue一级、二级路由设计
一、一级路由设计 一级路由是指直接映射到应用程序中顶级页面或组件的路由。这些路由通常定义在Vue Router的配置中,作为应用程序导航结构的基础。 直接映射:一级路由直接映射到URL路径和Vue组件,没有嵌套关系。顶级导航:它们通…...
python爬虫:将知乎专栏文章转为pdf
欢迎关注本人的知乎主页~ 实现思路 用户输入专栏ID: 代码首先提示用户输入一个知乎专栏的ID,默认值为 c_1747690982282477569。输入的ID用于构建API请求的URL。 发送HTTP请求: 使用 requests.get() 向知乎API发送GET请求,获取指定…...
嵌入式笔记(入门系列2)
目录 宏函数 预处理器#include 内存泄漏 内存对齐 堆与栈 Malloc 和 New Inline 宏函数 宏函数,宏函数,实际上就是让宏像函数一样被使用。宏函数以函数形式的方式进行入参,但是返回结果是通过表达式求值得到。话说的抽象,我…...
并发编程多线程
1.线程和进程的区别? 进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间线程更轻量,线程上下文切换成本一般上要比进程上下文…...
【十八】MySQL 8.0 新特性
MySQL 8.0 新特性 目录 MySQL 8.0 新特性 概述 简述 1、数据字典 2、原子数据定义语句 3、升级过程 4、会话重用 5、安全和账户管理 6、资源管理 7、表加密管理 8、InnoDB增强功能 9、字符集支持 10、增强JSON功能 11、数据类型的支持 12、查询的优化 13、公用…...
巨潮股票爬虫逆向
目标网站 aHR0cDovL3dlYmFwaS5jbmluZm8uY29tLmNuLyMvSVBPTGlzdD9tYXJrZXQ9c3o 一、抓包分析 请求头参数加密 二、逆向分析 下xhr断点 参数生成位置 发现是AES加密,不过是混淆的,但并不影响咱们扣代码 文章仅提供技术交流学习,不可对目标服…...
传知代码-从零开始构建你的第一个神经网络
代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 从零开始构建你的第一个神经网络 在本教程中,我们将使用PyTorch框架从零开始构建一个简单的卷积神经网络(CNN),用于图片二分类任务。CNN 是一种深度学习模型&#…...
大厂面试真题:SpringBoot的核心注解
其实理解一个注解就行了@SpringBootApplication,我们的启动类其实就加了这一个 但是这么答也不行,因为面试官要的答案肯定不止这一个 我们打开SpringBootApplication的源码,会发现上面加了一堆的注解 相对而言比较重要是下面三个…...
Java设计模式—面向对象设计原则(五) ----->迪米特法则(DP) (完整详解,附有代码+案例)
文章目录 3.5 迪米特法则(DP)3.5.1 概述3.5.2 案例 3.5 迪米特法则(DP) 迪米特法则:Demeter Principle,简称DP 3.5.1 概述 只和你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to stranger…...
docker多阶段镜像制作,比如nginx镜像,编译+制作
镜像制作, nginx的源码包 把nginx源码拷贝到容器内 编译要用到gcc make , 以及扩展工具 pcre openssl # "pcre" perl compatibal regulaer expression 刚开始,可以两个终端, 一个手工操作(编译安装、拷贝、环境变量等)…...
大语言模型量化方法GPTQ、GGUF、AWQ详细原理
大语言模型量化的目的是减少模型的计算资源需求和存储占用,同时尽量保持模型的性能。以下是几种常见的量化方法的原理; 1. GPTQ (Gradient-based Post-training Quantization) GPTQ 是一种基于梯度的后训练量化方法,主要目的是在减少浮点计…...
《 C++ 修炼全景指南:十 》自平衡的艺术:深入了解 AVL 树的核心原理与实现
摘要 本文深入探讨了 AVL 树(自平衡二叉搜索树)的概念、特点以及实现细节。我们首先介绍了 AVL 树的基本原理,并详细分析了其四种旋转操作,包括左旋、右旋、左右双旋和右左双旋,阐述了它们在保持树平衡中的重要作用。…...
SAP 特别总账标识[SGL]
1. 特别总账标识(SGL)概述 1.1 定义与目的 特别总账标识(Special General Ledger, SGL)在SAP系统中用于区分客户或供应商的不同业务类型,以便将特定的业务交易记录到非标准的总账科目中。 定义:SGL是一个用于标记特殊业务类型的…...
认知杂谈77《简单:通往高手的技巧》
内容摘要: 在信息爆炸、关系复杂的时代,简单是复杂背后的真谛。简单如“112”,是智慧的朴素呈现。简单有强大力量,像清泉般纯净,如“我爱你”简单却有力,基础财务知识也体现其在理财中的作…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
