Redis的VALUE类型

本文详细介绍了Redis的数据结构,包括string、list、hash、set和sorted_set五种类型,以及它们各自的概念、操作和应用场景。Redis的单线程模型和使用kernel的epoll同步非阻塞的多路复用NIO技术使其能处理高并发请求。文章还讨论了Redis在统计用户登录天数、抢购秒杀、点赞计数等场景中的应用,并给出了具体操作示例。此外,提到了Redis如何通过位图操作实现高效的数据处理,如用户登录状态统计和活动参与人数计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis自我学习


Redis简介

继续往后推进,最近在学习redis的基本数据结构,首先在磁盘中的寻址空间为ms级别,而在内存中为ns级别,所以磁盘比内存在寻址上满了10W倍,也就是为什么mysql关系型数据库比NOSQL查询数据慢的原因之一。在MYSQL中,数据和索引都存储在硬盘中,真正查的时候要在内存中准备一个B+树(树干),把磁盘中的数据读到内存,再根据需要查找的数据索引再返回磁盘中寻找,找到之后再一次读进内存,依次循环,最终找到该记录。最终目的减少IO。
但是随着数据量大,mysql的性能会变低吗?不一定,如果表有索引,增删改会变慢,但查询速度需要区分,如果1个或少量查询,依然很快。但是并发量大的时候,会受硬盘带宽影响速度。(需要挨个从内存走,需要等待前面查询完再走)。在redis诞生之前,也有一款内存数据库,memcache,但是这款数据库淘汰的原因是value并没有设定它的类型,而像JSON一样表示复杂的数据结构,这种结构限制了对数据的操控,所以诞生了redis。
redis的value可以有5种类型,这不仅仅是有类型那么简单,也是因为redis对每种类型定义了众多操作。
redis是单进程、单线程、单实例的,可以并发很多请求,可是为什么单进程单线程却能速度变得很快呢?我们知道在Linux下真正实现AIO是很困难的,即便现在真正有了AIO的产品,也不是很理想,所以redis采用了kernel的epoll同步非阻塞的多路复用NIO技术(这一块可以看下netty与socket编程)。
在这里插入图片描述
Redis的默认端口号为6379,默认建立了16个库,库和库是分离的,相当于Mysql的表。

redis安装步骤

在centos上安装。
在这里插入图片描述

value类型

总结一下redis的常用5种类型。redis的key只能是字符串类型,而value却可以有很多种类型。value类型可以为string、set、sortset、list、hash。

redis的string类型

概念

string类型有字符串操作、数值操作以及位图操作。
在这里插入图片描述
对于各个操作,可以用help @string命令查看
在这里插入图片描述
在redis中有个很重要的概念,二进制安全。
在这里插入图片描述
Redis拿的是字节流,不会破坏编码,防止多语言开发的时候,需要转换类型。在数值中,99999长度为5,就是一个字节取。若计算
则拿出来转换为数值,会更新key的encoding的int,encoding存在的意义在于(对key做了优化)不需要再进行判断是否可以转为int类型,不需要排测过程,是一个加速过程(忽略)直接累加。而中文需要根据xshell的编码格式。Redis一定是要在用户端沟通编码与解码,redis内部是没有数据类型的,都是字节流存储。方便各种语言对redis进行操作。
在这里插入图片描述
对于中文的获取,必须加 --raw才能根据xshell的格式取获取不同编码的中文。
1.对于字符串操作,主要的操作是set,get。
2.对于数值操作,主要是加一个数字或者减一个数字
3.对于位图操作,setbit k1 5 1意思是在第5个二进制位上把0置为1
bitpos k1 1 1 1意思是第一个1为查找二进制位为1的位置,后两位是第几个字节。这里是从第一个字节到第一个字节。
bittop and endkey k1 k2 将k1与k2按位与操作,并返回至endkey键中。

setnx是一个很重要的概念,此方法与缓存击穿问题有关,能让单个线程通过setnx再加上过期时间解决缓存击穿问题。

在setbit的offset是下面的offset。
Setbit k1 5 1 <=====> 0000 1000
Bitpos是bitpos k1 1 1 1 意思是从第一个字节到第一个字节中寻找第一个出现二进制位为1的偏移量,需要再加上前面8位。
在这里插入图片描述
在这里插入图片描述

应用场景

位图的应用场景1:统计用户登录天数,且窗口随机。也就是假设需要在一年的最后2周之内计算用户的登录天数。用位图。
ket存的是用户名,分为365个bit位,某一天出现了登录状态,则某一位置为1.下列的-2 -1是redis支持反向索引,-2 -1也就是最后16天的统计。
一个用户一年只需要46字节存储
在这里插入图片描述
位图的应用场景2:618送礼物,需要准备多少礼物?
首先要确定活跃用户的统计,key把年份记录下来,而value的二进制位则代表用户。通过bitop or统计去年618前后3天的活跃人员数,再用bitcount统计。
在这里插入图片描述
数值的应用场景:抢购,秒杀,点赞,规避并发下对数据库的事务的操作,完全由redis内存操作代替。

Redis的List类型

在这里插入图片描述
在这里插入图片描述
list可以模拟不同的数据结构,栈、队列、数组和阻塞队列。
模拟栈,需要同向命令。比如:
在这里插入图片描述
在这里插入图片描述
模拟队列需要反向命令
在这里插入图片描述
在这里插入图片描述
模拟数组的下标获取值
在这里插入图片描述
在这里插入图片描述
模拟阻塞单播队列

在这里插入图片描述
等待获取k3的第一个值
在这里插入图片描述

在这里插入图片描述

此时输入队列一个元素,那么就不阻塞了。

Redis的Hash类型

redis本身就是Key-value,这里hash也是key-value结构。
在这里插入图片描述
应用场景:比如:再购物车上一个用户对应不同商品与数量。也可以有详情页。
Redis是内存的数据库,对值的操作非常快,当有了详情页,有很多很多字段的信息,给出名字拿出所有的values就出来了。点赞次数,浏览的次数,被收藏的次数,纪要被查询又要被计算,hash支持数值的计算。

Redis的Set类型

set是一种无重复的集合,不维护排序。
在这里插入图片描述
可以取两个key的交集
在这里插入图片描述
还可以用Sinterstore dest k1 k2

Sinterstore dest k1 k2 放到store中,为什么要有这个命令呢?但如果有这样需要,既要k2 k3数据也要k2 k3的交集,这个时候把k2 k3 的交集放到redis,有一次IO的时间。
在这里插入图片描述
并集SUNION
在这里插入图片描述
差集SDIFF,但是有方向性
在这里插入图片描述
在这里插入图片描述
set可以用来抽奖,抽奖方式有两种,一种是人多奖品少,还有一种是人少奖品多
在这里插入图片描述
spop是随机取出一个value。

Redis的Sorted_Set类型

类型(有序集) sorted set首先是set,需要有个维度,分值维度,按照分值进行排序。
如果以分值为1,按照字典序排序。
在这里插入图片描述
zrange与zrangebyscore
在这里插入图片描述

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

这里的zrevrange怎么取的呢?因为有双向链表,取的话是从小到大。

对相同的值做并集,这里可以用weights1 0.5赋值权重。
在这里插入图片描述
sorted_set内部数据结构用的是跳表
在这里插入图片描述
这里是随机造层。

假设需要找x23,那么在第一层中找到11,11还是比23小,那么往下去第二层,第二层中比x22大,但是比x45小,这时在下去,去找到x23。

牺牲了空间,成全了速度。越往上点越少。

<think>我们已知RedisValue是StackExchange.Redis库中常用的类型,它通常用于表示Redis中的各种值,包括字符串、整数等。在C#中,我们经常需要将RedisValue数组(RedisValue[])转换为字符串数组(string[])。根据引用[2]和引用[4]中提供的数组转换思路,我们可以采用类似的方法。 在StackExchange.Redis中,RedisValue类型可以隐式转换为string类型,也可以显式转换。因此,我们可以使用Array.ConvertAll方法(如引用[2]所示)或者使用LINQ的Select方法(如引用[4]所示)来实现转换。 方法1:使用Array.ConvertAll string[] stringArray = Array.ConvertAll(redisValueArray, value => (string)value); 方法2:使用LINQ的Select string[] stringArray = redisValueArray.Select(value => (string)value).ToArray(); 注意:由于RedisValue可以表示非字符串类型(如整数),在转换时如果确保数组中都是字符串,或者我们想将非字符串表示为字符串形式,可以使用ToString()方法。但通常,如果RedisValue存储的是字符串,直接强制转换为string是安全的。如果存储的是整数等,强制转换也会将其转换为字符串形式(例如整数123会变成字符串"123")。另外,也可以使用value.ToString(),但要注意如果value是null,ToString()会抛出异常,而(string)null则返回null。 因此,更安全的方式是使用强制转换((string)value)或者使用value.HasValue ? value.ToString() : null。但是,在StackExchange.Redis中,RedisValue是一个结构体,它内部可以包含null,并且强制转换为string时,如果内部是null,则转换结果为null。所以,使用强制转换是安全的。 示例代码: ```csharp using StackExchange.Redis; // ... 假设已经获取了RedisValue数组 RedisValue[] redisValues = ...; // 从Redis获取的值 // 方法1:使用Array.ConvertAll string[] stringArray1 = Array.ConvertAll(redisValues, value => (string)value); // 方法2:使用LINQ string[] stringArray2 = redisValues.Select(v => (string)v).ToArray(); ``` 如果RedisValue数组中包含非字符串类型,比如整数,那么强制转换也会将其转换为字符串表示。例如,RedisValue中存储整数123,转换后就是字符串"123"。 另外,如果数组中包含null,转换后对应的元素也是null,因此需要根据后续使用情况注意处理null值。 根据引用[4]中展示的将int数组转换为字符串数组的方法,我们这里也是类似的思路,只是转换函数不同。 因此,以上两种方法都可以实现将RedisValue数组转换为字符串数组。 注意:在StackExchange.Redis中,RedisValue类型已经设计为与基础类型(如string, int等)之间可以方便地转换,所以上述转换通常是安全的。 如果用户需要将整个数组连接成一个字符串(如引用[4]中的string.Join),可以在转换后再使用string.Join。 例如:string result = string.Join(",", stringArray1); 如果用户的问题中RedisValue数组包含的是二进制数据(比如byte[]),那么转换方式会不同。但是,根据问题描述,用户希望转换为字符串数组,所以假设每个元素都是可转换为字符串的(即Redis中的字符串类型或者整数等基本类型)。如果遇到二进制数据,需要根据具体需求进行Base64编码或者使用其他编码方式转换为字符串,但这种情况不在本问题范围内。 因此,针对用户的问题,我们给出上述两种转换方法。 相关问题: 1. 在C#中如何将RedisValue数组转换为整数数组? 2. 在StackExchange.Redis中如何处理RedisValue为null的情况? 3. 如何将字节数组(byte[])转换为RedisValue?</think>### 在 C# 中将 RedisValue 数组转换为字符串数组 在 StackExchange.Redis 库中,`RedisValue` 类型表示 Redis 存储的数据(字符串、整数、二进制等)。将 `RedisValue[]` 转换为 `string[]` 的常用方法如下: #### 方法 1:使用 `Select` + 显式转换(推荐) ```csharp using StackExchange.Redis; using System.Linq; RedisValue[] redisValues = ...; // 从 Redis 获取的数组 string[] stringArray = redisValues .Select(v => (string)v) // 显式转换为 string .ToArray(); ``` #### 方法 2:使用 `Array.ConvertAll` ```csharp using StackExchange.Redis; RedisValue[] redisValues = ...; string[] stringArray = Array.ConvertAll( redisValues, v => (string)v ); ``` #### 关键说明: 1. **类型安全** - 使用 `(string)v` 显式转换时,若 `RedisValue` 包含非字符串数据(如整数),会自动转换为字符串表示(如 `"123"`)。 - 若值为 `null`,转换结果为 `null`(需后续处理空值)。 2. **性能优化** - `Select().ToArray()` 在 LINQ 中高效处理大型数组[^2][^4]。 3. **二进制数据处理** 若 `RedisValue` 存储二进制数据(如 `byte[]`),需额外解码: ```csharp stringArray = redisValues .Select(v => v.IsNull ? null : Encoding.UTF8.GetString((byte[])v)) .ToArray(); ``` #### 示例场景 ```csharp // 从 Redis 获取列表数据 IDatabase db = redis.GetDatabase(); RedisValue[] values = db.ListRange("myList"); // 转换为字符串数组 string[] items = values.Select(v => (string)v).ToArray(); // 输出结果: ["A", "B", "C"] Console.WriteLine($"[{string.Join(", ", items)}]"); ``` ### 注意事项 - **空值处理**:转换后可能包含 `null`,建议使用 `.Where(v => v != null)` 过滤。 - **编码一致性**:确保字符串编码与 Redis 存储一致(默认为 UTF-8)。 - **性能**:大型数组优先选择 `Select().ToArray()` 或 `Array.ConvertAll`[^2][^4]。 --- ### 相关问题 1. 如何将 RedisValue 数组直接转换为整数数组(`int[]`)? 2. StackExchange.Redis 中如何处理 RedisValue 为 `null` 的情况? 3. 在 C# 中如何将字节数组(`byte[]`)高效转换为字符串?[^3] 4. 如何将字符串数组连接为单个字符串(如 `"A,B,C"`)?[^4] [^1]: 数组转换基础方法参考 [^2]: `Array.ConvertAll` 的高效实现 [^3]: 字节数组到字符串的转换技巧 [^4]: 数组元素连接为字符串的最佳实践
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值