Redis五大数据类型全解析:从入门到实战

引言

在如今的互联网应用里,几乎没有哪个系统离得开 Redis。首页的商品信息、用户的登录状态、接口的限流计数、实时的排行榜......背后往往都有 Redis 的身影。它是目前最流行的内存数据库,也是后端工程师面试必问、日常必用的中间件之一。

很多刚接触 Redis 的同学,第一反应是"它不就是个缓存吗"。其实 Redis 远不止缓存这么简单,它丰富的数据类型能支撑起缓存、计数器、排行榜、消息队列、分布式锁等大量场景。这篇文章我会先讲清楚 Redis 是什么、为什么快,然后逐个拆解它的五种基础数据类型,每种都配上命令示例和典型使用场景。

一、Redis 是什么

Redis(Remote Dictionary Server,远程字典服务) ​是一个开源的、基于内存的高性能 键值对(Key-Value)存储系统。它既可以当数据库,也可以当缓存和消息中间件。

Redis 的几个核心特点:

  1. 基于内存:数据存在内存里,读写速度极快(单机轻松 10W+ QPS),这是它快的根本原因。
  2. 单线程:核心命令处理是单线程的,避免了多线程切换和锁竞争的开销(注:Redis 6.0 之后引入了多线程,但主要用于网络 IO,命令执行仍是单线程)。
  3. 持久化:虽然数据在内存,但可以通过 RDB 快照或 AOF 日志把数据落盘,防止宕机丢失。
  4. 丰富的数据类型:除了 String,还支持 List、Hash、Set、ZSet 等,这是它区别于普通 KV 缓存(如 Memcached)的关键。
  5. 支持多种高级特性:过期时间、发布订阅、事务、Lua 脚本、主从复制、哨兵、集群等。

它为什么这么快? 归纳起来就是:纯内存操作 + 单线程避免锁竞争 + IO 多路复用 + 高效的数据结构。

二、安装与启动

最简单的体验方式是用 Docker 跑一个 Redis:

bash

复制代码
# 拉取镜像并启动
docker run -d --name redis -p 6379:6379 redis

# 进入 Redis 命令行客户端
docker exec -it redis redis-cli

连接成功后输入 PING,返回 PONG 就说明 Redis 正常运行了:

plaintext

复制代码
127.0.0.1:6379> PING
PONG

本文后续的命令示例,都在这个 redis-cli 命令行里演示。

三、五种基础数据类型

Redis 的 Key 都是字符串,但 Value 可以是不同类型。最基础、最常用的有五种:String、Hash、List、Set、ZSet。下面逐个介绍。

3.1 String(字符串)

String 是最基础的类型,一个 Key 对应一个字符串值,这个字符串最大能存 512MB。它不仅能存普通文本,还能存整数、浮点数、JSON、二进制等。

常用命令:

命令 作用 示例
SET / GET 设置 / 获取 SET name zhangsan → GET name
SETNX 不存在才设置(分布式锁基础) SETNX lock 1
SETEX 设置并指定过期时间(秒) SETEX code 60 123456
INCR / DECR 原子自增 / 自减 INCR count
MSET / MGET 批量设置 / 获取 MSET a 1 b 2 → MGET a b
APPEND 追加内容 APPEND name " hello"

演示:

plaintext

复制代码
127.0.0.1:6379> SET user:1:name zhangsan
OK
127.0.0.1:6379> GET user:1:name
"zhangsan"

127.0.0.1:6379> INCR view:count
(integer) 1
127.0.0.1:6379> INCR view:count
(integer) 2

典型场景: 缓存对象(JSON 字符串)、计数器(点赞数、浏览量)、分布式锁(SETNX + 过期时间)、验证码(SETEX)、Session 共享。

3.2 Hash(哈希)

Hash 是一个 Key 对应一个 field-value 映射表 ,特别适合用来存储对象,就像 Java 里的 Map<String, Map<String, String>>。

常用命令:

命令 作用 示例
HSET / HGET 设置 / 获取某个 field HSET user:1 name zhangsan → HGET user:1 name
HMSET / HMGET 批量设置 / 获取 HMSET user:1 name lisi age 20
HGETALL 获取所有 field-value HGETALL user:1
HDEL 删除某个 field HDEL user:1 age
HLEN field 数量 HLEN user:1
HINCRBY 给 field 的整数加值 HINCRBY user:1 age 1

演示:

plaintext

复制代码
127.0.0.1:6379> HMSET user:1 name zhangsan age 18 city beijing
OK
127.0.0.1:6379> HGET user:1 name
"zhangsan"
127.0.0.1:6379> HGETALL user:1
1) "name"
2) "zhangsan"
3) "age"
4) "18"
5) "city"
6) "beijing"

典型场景: 存储对象(用户信息、商品信息)。相比把对象序列化成 JSON 存 String,Hash 可以单独修改某个字段而不必整个重新序列化,也更节省内存(字段少时用 ziplist 压缩存储)。

3.3 List(列表)

List 是一个有序、可重复 的字符串列表,底层是双向链表,所以它头尾操作极快,中间操作较慢。

常用命令:

命令 作用 示例
LPUSH / RPUSH 从左 / 右插入 LPUSH mylist a b c
LPOP / RPOP 从左 / 右弹出 LPOP mylist
LRANGE 按区间取元素 LRANGE mylist 0 -1(取全部)
LLEN 列表长度 LLEN mylist
LREM 删除指定元素 LREM mylist 1 a
BLPOP / BRPOP 阻塞式弹出(消息队列基础) BRPOP mylist 0

演示:

plaintext

复制代码
127.0.0.1:6379> LPUSH mylist a b c
(integer) 3
127.0.0.1:6379> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> RPOP mylist
"a"

注意 LPUSH 是从左边依次插入,所以最后 LRANGE 出来是倒序的(c b a)。

典型场景: 消息队列(LPUSH 生产 + BRPOP 消费)、最新消息列表、粉丝关注列表、简单的栈(LPUSH + LPOP)。

3.4 Set(集合)

Set 是一个无序、不可重复 的字符串集合,基于哈希表实现,查找、判重的复杂度都是 O(1)。它最大的亮点是支持集合运算(交集、并集、差集)。

常用命令:

命令 作用 示例
SADD 添加元素 SADD tags java redis
SMEMBERS 查看所有元素 SMEMBERS tags
SISMEMBER 判断是否存在 SISMEMBER tags java
SREM 删除元素 SREM tags java
SCARD 元素数量 SCARD tags
SINTER 交集 SINTER set1 set2
SUNION 并集 SUNION set1 set2
SDIFF 差集 SDIFF set1 set2

演示:

plaintext

复制代码
127.0.0.1:6379> SADD user:1:friends lisi wangwu zhaoliu
(integer) 3
127.0.0.1:6379> SADD user:2:friends wangwu zhaoliu sunqi
(integer) 3

# 共同好友(交集)
127.0.0.1:6379> SINTER user:1:friends user:2:friends
1) "wangwu"
2) "zhaoliu"

典型场景: 去重(防止重复点赞、重复抽奖)、共同好友/共同关注(交集)、标签系统、随机抽奖(SPOP)。

3.5 ZSet(有序集合)

ZSet 是 Set 的"升级版",每个元素都关联一个 score(分数) ​,元素按 score 从小到大排序。它既保留了 Set 的"唯一性",又多了"排序"能力,是排行榜场景的首选。

常用命令:

命令 作用 示例
ZADD 添加元素(带分数) ZADD rank 100 zhangsan 95 lisi
ZRANGE 按分数从小到大取 ZRANGE rank 0 -1
ZREVRANGE 按分数从大到小取 ZREVRANGE rank 0 -1
ZRANGEBYSCORE 按分数区间取 ZRANGEBYSCORE rank 90 100
ZSCORE 获取某元素分数 ZSCORE rank zhangsan
ZRANK 获取排名(从小到大) ZRANK rank lisi
ZREM 删除元素 ZREM rank lisi
ZINCRBY 给分数加值 ZINCRBY rank 5 zhangsan

演示:

plaintext

复制代码
127.0.0.1:6379> ZADD rank 100 zhangsan 95 lisi 88 wangwu
(integer) 3

# 从高到低排名(排行榜)
127.0.0.1:6379> ZREVRANGE rank 0 -1 WITHSCORES
1) "zhangsan"
2) "100"
3) "lisi"
4) "95"
5) "wangwu"
6) "88"

# 给 zhangsan 加 5 分
127.0.0.1:6379> ZINCRBY rank 5 zhangsan
"105"

典型场景: 排行榜(游戏积分、商品销量、热搜榜)、带权重的队列、延时队列(用时间戳做 score)。

四、五种类型速查对比

类型 结构特点 是否有序 是否可重复 典型场景
String 单个值 --- --- 缓存、计数器、分布式锁
Hash field-value 映射 否 field 不重复 存储对象
List 双向链表 是 是 消息队列、最新列表
Set 哈希集合 否 否 去重、共同好友
ZSet 带 score 的集合 是 否 排行榜、延时队列

五、实战:SpringBoot 整合 Redis

光会命令还不够,后端开发最终要在 Java 代码里操作 Redis。下面给一个 SpringBoot 整合 Redis 的最小示例。

5.1 引入依赖

xml

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池(可选,生产建议加) -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

5.2 配置连接

yaml

复制代码
spring:
  data:
    redis:
      host: localhost
      port: 6379
      # password: 123456
      database: 0

5.3 使用 StringRedisTemplate

java

复制代码
@Service
public class RedisService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // 缓存字符串
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // 计数器
    public Long incr(String key) {
        return redisTemplate.opsForValue().increment(key);
    }

    // Hash 存对象
    public void saveUser(String key, Map<String, String> user) {
        redisTemplate.opsForHash().putAll(key, user);
    }

    // List 队列
    public Long push(String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    // Set 添加
    public Long sadd(String key, String value) {
        return redisTemplate.opsForSet().add(key, value);
    }

    // ZSet 排行榜加分数
    public void zadd(String key, String member, double score) {
        redisTemplate.opsForZSet().add(key, member, score);
    }
}

StringRedisTemplate 对应的操作方法:opsForValue()(String)、opsForHash()(Hash)、opsForList()(List)、opsForSet()(Set)、opsForZSet()(ZSet),和上面讲的五种类型一一对应。

总结

这篇文章把 Redis 的基础脉络梳理了一遍:

  1. Redis 是什么:基于内存的高性能 Key-Value 存储,可当数据库、缓存、消息中间件;快的原因在于内存操作、单线程、IO 多路复用。
  2. 五种基础数据类型 :
    • String:最基础,缓存、计数器、分布式锁;
    • Hash:field-value 映射,适合存对象、局部更新;
    • List:有序可重复的双向链表,适合队列、最新列表;
    • Set:无序去重的集合,适合判重、共同好友;
    • ZSet:带 score 的有序集合,排行榜首选。
  3. SpringBoot 整合 :通过 StringRedisTemplate 的 opsForXXX() 方法即可方便地操作五种类型。

掌握这五种类型和它们的典型场景,是深入 Redis 的第一步。

相关推荐
瑞克-桑切斯2 小时前
PostgreSQL 14.4 源码部署 & 运维手册(CentOS7)
数据库·学习·postgresql
上海红同电子2 小时前
红同电子线束工厂100问|绝缘护套采购,材质PVC、TPE、PP该如何选型?
数据库·经验分享·职场和发展·产品运营·制造·材质
我不会插花弄玉2 小时前
5.Hash 【由浅入深-redis】
redis·算法·哈希算法
Nuanyt2 小时前
LeetCode Hot 100 · 双指针 3 题 Java
java·笔记·算法·leetcode·双指针
Wang's Blog2 小时前
Java 项目实战: 交友项目 - 圈子互动
java·开发语言·交友
Rain的Java大神之路2 小时前
北漂 13 年,我把 Java 家底钉成了这张知识图谱(全站免费)
java·后端·程序员
Amos_Web2 小时前
通过 Rspack 源码学 Rust(一):`mod`、`pub` 与 `use crate`/`use super`
后端
泡海椒2 小时前
JQuick-SQL “数据源 SPI”辨析:应用适配器与 Function SPI 的正确边界
数据库·驱动开发·sql
无毁的湖光-Al2 小时前
高可用之路-观测篇-那些年遇到过的指标幻觉
linux·数据库·tcp