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”,是智慧的朴素呈现。简单有强大力量,像清泉般纯净,如“我爱你”简单却有力,基础财务知识也体现其在理财中的作…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
boost::filesystem::path文件路径使用详解和示例
boost::filesystem::path 是 Boost 库中用于跨平台操作文件路径的类,封装了路径的拼接、分割、提取、判断等常用功能。下面是对它的使用详解,包括常用接口与完整示例。 1. 引入头文件与命名空间 #include <boost/filesystem.hpp> namespace fs b…...