Redis数据结构与应用场景:String、Hash、List、Set、ZSet
Redis数据结构与应用场景:String、Hash、List、Set、ZSet
分类: Redis
摘要: Redis的多种数据结构是其强大的基础,理解各数据结构的特性和应用场景对合理使用Redis至关重要。本文将深入剖析五种基础数据结构的底层原理,并结合Java实战代码展示其在真实项目中的最佳实践。
一、 引言
在当今的高并发互联网架构中,Redis 几乎成为了标配的中间件。很多开发者虽然每天都在使用 Redis,但往往局限于简单的 get、set 操作。实际上,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";

浙公网安备 33010602011771号