Redis基础指令

本文深入解析Redis中的五种主要数据结构:String、List、Hash、Set和Zset,包括其内部实现、操作命令及应用场景,揭示Redis高效存储的秘密。

String字符串

Redis 的字符串是动态字符串,是可以修改的字符串,内部结构实现上类似于 Java 的 ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,如图中所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。需要注意的是字符串最大长度为 512M。

set/get/exists/del/mset/mget/expire/setex/setnx/incr/incrby

List列表

Redis 的列表相当于 Java 语言里面的 LinkedList,注意它是链表。这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n),

当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收。

rpush/llen/lpop/rpop/lindex索引从0开始/ltrim/lrange

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成 quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间,而且会加重内存的碎片化。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next 。所以 Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

Hash字典

Redis 的字典相当于 Java 语言里面的 HashMap,它是无序字典。内部实现结构上同 Java 的 HashMap 也是一致的,同样的数组 + 链表二维结构。第一维 hash 的数组位置碰撞时,就会将碰撞的元素使用链表串接起来。

不同的是,Redis 的字典的值只能是字符串,另外它们 rehash 的方式不一样,因为 Java 的 HashMap 在字典很大时,rehash 是个耗时的操作,需要一次性全部 rehash。Redis 为了高性能,不能堵塞服务,所以采用了渐进式 rehash 策略。

渐进式 rehash 会在 rehash 的同时,保留新旧两个 hash 结构,查询时会同时查询两个 hash 结构,然后在后续的定时任务中以及 hash 的子指令中,循序渐进地将旧 hash 的内容一点点迁移到新的 hash 结构中。

当 hash 移除了最后一个元素之后,该数据结构自动被删除,内存被回收。

hset/hgetall/hlen/hget/hincrby

Set集合

Redis 的集合相当于 Java 语言里面的 HashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL。

当集合中最后一个元素移除之后,数据结构自动删除,内存被回收。

sadd/smembers/sismember/scard/spop

zset有序列表

zset 可能是 Redis 提供的最为特色的数据结构,它也是在面试中面试官最爱问的数据结构。它类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。它的内部实现用的是一种叫着「跳跃列表」的数据结构。

zset 中最后一个 value 被移除后,数据结构自动删除,内存被回收。

zadd/zrange/zrevrange/zcard/zscore/zrank/zrangebyscore/zrem

容器型数据结构的通用规则

1、create if not exists

如果容器不存在,那就创建一个,再进行操作。比如 rpush 操作刚开始是没有列表的,Redis 就会自动创建一个,然后再 rpush 进去新元素。

2、drop if no elements

如果容器里元素没有了,那么立即删除元素,释放内存。这意味着 lpop 操作到最后一个元素,列表就消失了。

过期时间

Redis 所有的数据结构都可以设置过期时间,时间到了,Redis 会自动删除相应的对象。需要注意的是过期是以对象为单位,比如一个 hash 结构的过期是整个 hash 对象的过期,而不是其中的某个子 key。

还有一个需要特别注意的地方是如果一个字符串已经设置了过期时间,然后你调用了 set 方法修改了它,它的过期时间会消失。

### Redis 基础概念 Redis 是一种基于内存的数据存储系统,它既可以作为数据库使用,也可以充当缓存和消息中间件。其设计目标是实现高性能读写操作,因此常用于需要快速访问数据的应用场景[^1]。 #### 数据类型 Redis 支持多种丰富的数据类型,包括字符串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)以及有序集合(Sorted Sets)。这些数据类型的灵活性使得 Redis 可以满足不同业务需求下的复杂数据处理任务。 #### 高效性与持久化机制 由于所有的键值对都保存在内存之中,这极大地提高了数据检索的速度。然而为了防止意外断电或其他情况造成数据丢失,Redis 提供了两种主要的持久化方式——RDB(快照)和 AOF(追加日志)。通过配置合适的策略可以平衡性能与安全性之间的关系[^4]。 --- ### Java 操作 Redis 方法介绍 当我们在开发过程中需要用到 Redis 时,通常会借助一些成熟的客户端库来进行交互。对于 Java 开发者来说,Jedis 和 Lettuce 是两个非常流行的选项。 以下是利用 Jedis 库连接并简单操作 Redis 的示例代码: ```java import redis.clients.jedis.Jedis; public class RedisExample { public static void main(String[] args) { // 创建 Jedis 实例对象, 连接到本地运行的 Redis 服务端口默认为6379. try (Jedis jedis = new Jedis("localhost")) { System.out.println("Connection to server sucessfully"); // 设置 key-value 对应关系 jedis.set("name", "John Doe"); // 获取指定key对应的value值 String value = jedis.get("name"); System.out.println("Stored string in redis:: "+ value); } } } ``` 上述例子展示了如何建立同 Redis Server 的链接,并完成基本设置(get/set)命令的操作流程。 --- ### 执行脚本功能概述 除了常规指令外,Redis 自版本2.6起还内置了一个Lua解释引擎允许用户编写自定义逻辑并通过 `EVAL` 或其他相关联的函数调用来执行它们[^2]。这种方式特别适用于那些希望减少多次往返通信开销或者确保原子性的场合下批量处理多条语句的情况[^3]。 例如下面这段简单的 Lua 脚本实现了增加计数器的功能: ```lua local current_value = tonumber(redis.call('get', KEYS[1])) if not current_value then current_value = 0 end current_value = current_value + ARGV[1] redis.call('set', KEYS[1], tostring(current_value)) return current_value ``` 可以通过如下方法加载至 Redis 并触发计算过程: ```bash EVAL "your lua script here" 1 counter_key increment_amount ``` 其中第一个参数代表要传递给脚本使用的 keys 数量;第二个以后则依次填入实际变量名及其对应数值。 --- ### 总结 综上所述,Redis 不仅具备卓越的表现力而且提供了多样化的特性集使其成为现代软件架构不可或缺的一部分。无论是构建实时分析平台还是管理分布式锁资源都能找到适合自己的解决方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值