Redis数据结构与应用场景:String、Hash、List、Set、ZSet

Redis数据结构与应用场景:String、Hash、List、Set、ZSet

分类: Redis
摘要: Redis的多种数据结构是其强大的基础,理解各数据结构的特性和应用场景对合理使用Redis至关重要。本文将深入剖析五种基础数据结构的底层原理,并结合Java实战代码展示其在真实项目中的最佳实践。


一、 引言

在当今的高并发互联网架构中,Redis 几乎成为了标配的中间件。很多开发者虽然每天都在使用 Redis,但往往局限于简单的 getset 操作。实际上,Redis 之所以高性能、高灵活,核心原因在于其丰富且设计精妙的数据结构。

Redis 不仅仅是简单的 Key-Value 存储引擎,它支持五种基础数据结构:String(字符串)、Hash(哈希)、List(列表)、Set(集合)、ZSet(有序集合)。理解这些数据结构的底层实现原理,是区分“会用 Redis”和“精通 Redis”的分水岭,也是应对高并发场景、解决实际问题的基石。

本文将从底层原理出发,结合 Java 语言(使用 Jedis 客户端)进行实战演示,帮助你彻底掌握 Redis 的核心数据结构。


二、 String:最基础的多面手

1. 原理深入

String 是 Redis 最基本的数据结构,但它不仅仅能存储字符串。在底层实现上,Redis 使用了 SDS(Simple Dynamic String,简单动态字符串)

SDS 相比 C 语言原生字符串有以下优势:
* O(1) 复杂度获取长度:SDS 结构体中记录了 len 属性,不需要遍历字符串。
* 杜绝缓冲区溢出:SDS 在进行修改时,会先检查空间是否满足要求,不满足则自动扩容。
* 二进制安全:SDS 不仅可以存储文本,还可以存储图片、音频等二进制数据,因为 SDS 使用 len 判断结束,而不是空字符 \0

编码优化:Redis 会根据存储的内容自动选择编码格式。
* int:存储整数。
* embstr:存储字符串长度小于等于 44 字节(Redis 5.0 版本标准),内存连续分配,一次分配即可。
* raw:存储字符串长度大于 44 字节,使用 SDS 结构。

2. 应用场景

  • 缓存对象:直接缓存 JSON 序列化后的用户对象。
  • 分布式锁:利用 SET key value NX PX timeout 实现互斥锁。
  • 计数器:视频播放量、文章点赞数,利用 INCR 原子操作。
  • 分布式 ID 生成:利用 INCR 生成全局唯一 ID。

3. 实战代码

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

public class StringDemo {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);

        // 场景1:分布式锁
        // set key value NX PX 10000
        // NX表示不存在才设置,PX表示过期时间毫秒
        String lockKey = "lock:product_101";
        String requestId = "uuid-123456";

        SetParams params = SetParams.setParams().nx().px(10000);
        String result = jedis.set(lockKey, requestId, params);

        if ("OK".equals(result)) {
            System.out.println("获取锁成功,执行业务逻辑...");
            // 业务逻辑执行完毕,释放锁(Lua脚本保证原子性)
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            jedis.eval(script, 1, lockKey, requestId);
        } else {
            System.out.println("获取锁失败,请重试");
        }

        // 场景2:文章阅读量计数
        String articleKey = "article:1001:views";
        jedis.set(articleKey, "0");
        // 原子递增
        jedis.incr(articleKey);
        jedis.incrBy(articleKey, 5);
        System.out.println("当前阅读量: " + jedis.get(articleKey));

        jedis.close();
    }
}

三、 Hash:结构化数据的利器

1. 原理深入

Hash 是一个键值对集合,适合存储对象。底层实现主要有两种编码:
* ziplist(压缩列表):当 Hash 对象保存的键值对数量小于 hash-max-ziplist-entries(默认512)且所有键值对的长度都小于 hash-max-ziplist-value(默认64字节)时使用。ziplist 是一块连续的内存空间,内存利用率极高,但增删改操作需要内存重分配,效率较低。
* hashtable(哈希表):当不满足 ziplist 条件时,转为 hashtable。Redis 的哈希表采用链地址法解决哈希冲突,且支持渐进式 Rehash,避免扩容时一次性操作导致的卡顿。

2. 应用场景

  • 对象存储:相比 String 存储整个 JSON,Hash 可以只修改对象中的某个字段(如用户年龄),减少网络开销,且无需反序列化整个对象。
  • 购物车:用户 ID 为 Key,商品 ID 为 Field,商品数量为 Value。添加商品即 HINCRBY,删除商品即 HDEL,获取购物车即 HGETALL

3. 实战代码

```java
import redis.clients.jedis.Jedis;
import java.util.Map;

public class HashDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);

    // 场景:电商购物车
    String cartKey = "cart:user_1001";
posted @ 2026-02-27 01:01  寒人病酒  阅读(1)  评论(0)    收藏  举报