Redis 键空间 & 五大类型

目录

环境与工具

[Redis 键空间 & 五大类型](#Redis 键空间 & 五大类型)

什么是键空间(Keyspace)

[1. String(字符串)](#1. String(字符串))

[2. List(链表,双端队列)](#2. List(链表,双端队列))

[3. Hash(哈希)](#3. Hash(哈希))

[4. Set(无序集合,去重)](#4. Set(无序集合,去重))

[5. ZSet(有序集合,排行榜)](#5. ZSet(有序集合,排行榜))

[6. 键空间运维](#6. 键空间运维)

[Spring Boot 集成 Redis(五大类型练习)](#Spring Boot 集成 Redis(五大类型练习))


环境与工具

在 WSL2 中用 Docker 拉起 redis:latest,映射 6379 和数据卷。

用 redis-cli 连上本地 Redis,完成 PING → PONG。

新建 Spring Boot 空项目,加入 spring-boot-starter-data-redis 依赖,跑通最简单的 StringRedisTemplate 读写。

具体实现:

一、环境准备

  1. 确认 WSL2 + Docker 安装

Windows 开启 WSL2,并安装 Ubuntu。

安装 Docker Desktop,设置后台引擎为 WSL2 集成。

在 WSL2 里输入:

bash 复制代码
docker --version

确认能用

二、Docker 拉起 Redis

  1. 拉取官方镜像:
bash 复制代码
docker pull redis:latest
  1. 启动容器(映射 6379 端口 & 挂载数据卷):
bash 复制代码
docker run -d \
  --name myredis \
  -p 6379:6379 \
  -v ~/redis-data:/data \
  redis:latest \
  redis-server --appendonly yes

-p 6379:6379 → 把容器端口映射到宿主机

-v ~/redis-data:/data → 把持久化数据挂载到宿主机

redis-server --appendonly yes → 开启 AOF 持久化

  1. 查看运行情况:
bash 复制代码
docker ps

三、使用 redis-cli 测试

  1. 进入容器内运行 redis-cli:
bash 复制代码
docker exec -it myredis redis-cli
  1. 测试连接:
bash 复制代码
127.0.0.1:6379> PING
PONG

说明 Redis 已经启动成功。

Redis 键空间 & 五大类型

什么是键空间(Keyspace)

在 Redis 里,所有数据都是以键值对 (key-value) 的形式存储的。

键(key)= 唯一的名字(字符串)

值(value)= 可以是任意一种数据结构

Redis 内部就像有一个 巨大的字典(hash table),里面装满了这些 key-value

这个全局字典就叫做键空间

简单理解:

MySQL 有很多数据库,每个数据库里有很多表,每张表里有行。

Redis 有一个键空间,所有的 key 都放在这里,每个 key 指向一种数据类型的值

所以键空间意思就是所有键的存放空间

1. String(字符串)

bash 复制代码
SET name "alice"         # O(1)
GET name                 # "alice"

INCR counter             # 自增(不存在时会设为 0 再 +1)
INCR counter             # 再加 1 → counter = 2

EXPIRE counter 10        # 设置 10 秒过期
TTL counter              # 查看剩余寿命

GETRANGE name 0 2        # 截取子串 → "ali"

MSET a 100 b 200         # 一次设置多个键
MGET a b                 # 一次获取多个键

INCR全称 INCRement,含义自增

EXPIRE 全称 EXPIRE(动词,过期),含义为某个键设置生存时间(TTL)

语义是告诉 Redis 这个键在 N 秒后过期

TTL全称是 Time To Live(生存时间),含义是返回某个键剩余还能活多久(单位秒)

GETRANGE 全称是GET RANGE,含义是获取字符串值的指定范围子串

参数:起始下标、结束下标(包含)

MSET: Multi SET(一次设置多个键值对)
MGET: Multi GET(一次获取多个键值)

前缀 M 表示批量操作

2. List(链表,双端队列)

bash 复制代码
LPUSH nums 1 2 3         # 左插入 → nums = [3,2,1]
RPUSH nums 4 5           # 右插入 → nums = [3,2,1,4,5]

LRANGE nums 0 -1         # 遍历 → ["3","2","1","4","5"]

LPOP nums                # 从左取一个 → "3"
BLPOP nums 5             # 阻塞式取(等待 5 秒)

LPUSH

L = Left(左边) PUSH = 入栈 / 插入

含义是从 左边(头部)插入一个或多个元素到列表。

LPUSH nums 1 2 3 把 1,2,3 依次插入左边,结果是 [3,2,1]

RPUSH

R = Right(右边)

PUSH = 插入

含义是从 右边(尾部)插入一个或多个元素

RPUSH nums 4 5 在右边插入,结果是 [3,2,1,4,5]

LRANGE

L = List

RANGE = 范围

含义是获取列表中指定范围的元素

参数是起始索引和结束索引,支持负数索引(-1 表示最后一个)

LRANGE nums 0 -1 → 取出整个列表

LPOP

L = Left(左边)

POP = 出栈 / 移除并返回

含义是从左边弹出一个元素,并返回该值

LPOP nums → 返回 "3",列表变成 [2,1,4,5]

BLPOP

B = Blocking(阻塞式)

LPOP = 左出栈

含义是从左边弹出一个元素,如果列表为空,就阻塞等待一段时间(直到有元素被插入,或超时)

BLPOP nums 5 → 如果 5 秒内有人 LPUSH 新值,就会立即返回,否则超时

3. Hash(哈希)

bash 复制代码
HSET user:1 name "alice" age 20
HGET user:1 name
HGETALL user:1

HINCRBY user:1 age 1     # 年龄 +1 → age=21
HEXISTS user:1 email     # 检查 email 是否存在

HSET

H = Hash

SET = 设置

含义是往哈希表里设置某个字段的值

HGET

H = Hash

GET = 获取

含义是获取哈希表里某个字段的值

HGETALL

ALL = 全部

含义是一次性取出哈希表里的所有字段和值

HINCRBY

INCRBY = increase by(增加多少)

含义是让某个字段的数值加上指定增量

HEXISTS

EXISTS = 是否存在

含义是检查某个字段是否存在

4. Set(无序集合,去重)

bash 复制代码
SADD tags redis nosql cache
SMEMBERS tags            # 查看所有成员
SISMEMBER tags redis     # 是否存在 → 1

SADD tags2 redis db
SINTER tags tags2        # 交集 → redis

SCARD tags               # 集合大小

SADD

S = Set

ADD = 添加

含义是向集合中添加一个或多个元素(自动去重)

SADD tags redis nosql cache = 向 tags 集合里加入 3 个元素

SMEMBERS

S = Set

MEMBERS = 成员们

含义是返回集合里的所有成员

SMEMBERS tags = 列出集合 tags 的全部元素

SISMEMBER

S = Set

ISMEMBER = 是否是成员

含义是判断某个值是不是集合中的元素(返回 1 表示存在,0 表示不存在)

SISMEMBER tags redis = 检查 redis 是否在集合里

SINTER

S = Set

INTER = Intersection(交集)

含义是返回多个集合的交集

SINTER tags tags2 = tags ∩ tags2

SCARD

S = Set

CARD = Cardinality(集合基数 = 元素个数)

含义是返回集合里元素的数量

SCARD tags 集合里有多少元素

5. ZSet(有序集合,排行榜)

bash 复制代码
ZADD scores 100 "Alice" 200 "Bob" 150 "Cindy"
ZRANGE scores 0 -1 WITHSCORES      # 按分数升序
ZREVRANGE scores 0 -1 WITHSCORES   # 按分数降序(排行榜)

ZINCRBY scores 10 "Alice"          # Alice 分数+10
ZREMRANGEBYRANK scores 0 0         # 删除排名最末 1 个

Redis 的 ZADD 命令要求严格按照 score member(分数在前,成员在后) 的顺序成对传入参数

ZADD

Z = ZSet (Sorted Set)

ADD = 添加

含义是往有序集合里添加一个或多个元素,并指定分数(score)

ZADD scores 100 "Alice" → 插入 "Alice",分数 = 100

ZRANGE

Z = ZSet

RANGE = 范围

含义是按分数升序,取指定下标范围的成员

ZRANGE scores 0 -1 → 获取所有元素,按分数从小到大排序

ZREVRANGE

Z = ZSet

REV = Reverse(反向)

RANGE = 范围

含义是按分数降序,取指定下标范围的成员

ZREVRANGE scores 0 -1 → 排行榜模式,从高分到低分

WITHSCORES 用于同时返回成员的分数

ZINCRBY

Z = ZSet

INCRBY = Increase by(增加多少)

含义是给某个成员的分数加上指定值

ZINCRBY scores 10 "Alice" → "Alice" 的分数 +10

ZREMRANGEBYRANK

Z = ZSet

REM = Remove(删除)

RANGE = 范围

BYRANK = 根据排名

含义是删除按排名排序后处于某个范围的元素

ZREMRANGEBYRANK scores 0 0 → 删除分数最低的 1 个

要删除分数最高的 3 个的成员,可以这样写:

bash 复制代码
ZREMRANGEBYRANK key 0 2  # 错误:这会删除分数最低的3个

# 正确做法(删除分数最高的3个):
ZREMRANGEBYRANK key -3 -1

支持负数索引(-1 表示分数最高的成员)

6. 键空间运维

bash 复制代码
SCAN 0 MATCH "user:*" COUNT 10   # 分批扫描键
DEL name                         # 删除
UNLINK nums                      # 异步删除(避免阻塞)

1. SCAN 0 MATCH "user:*" COUNT 10

作用:扫描键空间,分批返回 key,避免一次性返回太多阻塞 Redis。

参数:

0 → 游标位置,初始必须从 0 开始。返回结果里会带一个新的游标,下次继续扫描时用。直到返回 0 说明扫描完了。

MATCH "user:*" → 匹配模式,这里就是扫描所有以 user: 开头的键。
COUNT 10 → 建议每次返回 10 个 key

这个 COUNT 10 的意思是:我建议 Redis 每次最多返回 10 个 key

但 Redis 不会严格保证一定就是 10 个。可能返回 3 个、也可能 15 个

为什么要用 SCAN 而不是 KEYS *?

KEYS * 会一次性返回所有 key,可能导致 Redis 阻塞(特别是 key 很多时)

SCAN 是 渐进式迭代,对性能更安全。

2. DEL name

DEL = delete

作用:立即删除 key name 以及对应的 value。

特点:

同步删除(马上执行)

如果 value 特别大(比如一个包含百万条元素的 List),会阻塞 Redis 一段时间

3. UNLINK nums

UNLINK = unlink(断开链接)

作用:把 key nums 标记为删除,但实际释放内存的操作交给后台线程异步执行。

好处:不会阻塞主线程,适合删除大对象。

区别:

DEL → 立即释放内存(同步,可能卡顿)

UNLINK → 异步释放内存(更安全)

总结

SCAN:安全地扫描所有 key(代替 KEYS)

DEL:立即删除 key(小对象可用)

UNLINK:异步删除 key(大对象推荐)

Spring Boot 集成 Redis(五大类型练习)

  1. 用 [Spring Initializr](https://start.spring.io/) 创建项目:

Project: Maven / Gradle

Language: Java

Spring Boot: 最新稳定版

Dependencies: Spring Web, Spring Data Redis

  1. Maven 依赖(pom.xml):
XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置 Redis 连接

在 application.yml 中写:

XML 复制代码
spring:
  data:
    redis:
      port: 6379
      host: localhost

注入 StringRedisTemplate 和 RedisTemplate

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.Set;

@RestController
@RequestMapping("/redis")
public class RedisDemoController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // String 示例
    @GetMapping("/string")
    public String stringOps() {
        stringRedisTemplate.opsForValue().set("name", "alice");
        return stringRedisTemplate.opsForValue().get("name");
    }

    // List 示例
    @GetMapping("/list")
    public List<String> listOps() {
        stringRedisTemplate.opsForList().leftPushAll("nums", "1", "2", "3");
        return stringRedisTemplate.opsForList().range("nums", 0, -1);
    }

    // Hash 示例
    @GetMapping("/hash")
    public Map<Object, Object> hashOps() {
        stringRedisTemplate.opsForHash().put("user:1", "name", "bob");
        stringRedisTemplate.opsForHash().put("user:1", "age", "20");
        return stringRedisTemplate.opsForHash().entries("user:1");
    }

    // Set 示例
    @GetMapping("/set")
    public Set<String> setOps() {
        stringRedisTemplate.opsForSet().add("tags", "redis", "nosql", "cache");
        return stringRedisTemplate.opsForSet().members("tags");
    }

    // ZSet 示例
    @GetMapping("/zset")
    public Set<String> zsetOps() {
        stringRedisTemplate.opsForZSet().add("scores", "Alice", 100);
        stringRedisTemplate.opsForZSet().add("scores", "Bob", 200);
        return stringRedisTemplate.opsForZSet().reverseRange("scores", 0, -1);
    }
}

启动项目 & 测试接口

Spring Boot 项目跑在 http://localhost:8080

GET http://localhost:8080/redis/string → "alice"

GET http://localhost:8080/redis/list → ["3","2","1"]

GET http://localhost:8080/redis/hash → {"name":"bob","age":"20"}

GET http://localhost:8080/redis/set → ["redis","nosql","cache"]

GET http://localhost:8080/redis/zset → ["Bob","Alice"]

Template = Spring 的操作模板工具类,封装常用 API,简化操作,类似 JdbcTemplate、RestTemplate

String = 说明 key 和 value 都用字符串序列化,存进去/取出来都是明文

所以 StringRedisTemplate = 专门操作字符串类型的 Redis 工具类模板
ops = operations(操作入口)

value = Redis 的 String 类型(键值对里的值)

opsForValue() = 获取操作 String 类型数据的工具
ops = operations(操作入口)

List = Redis 的 List 类型(链表)

opsForList() = 获取操作 Redis List 的工具
leftPushAll对应 Redis 的 LPUSH 命令,往列表左边批量插入多个元素

range对应 Redis 的 LRANGE 命令,按下标区间获取列表元素
put 对应 Redis 的 HSET 命令

entries 对应 Redis 的 HGETALL 命令

相关推荐
235162 小时前
【LeetCode】3. 无重复字符的最长子串
java·后端·算法·leetcode·职场和发展
nandao1582 小时前
springBoot 集成Neo4j 实战演示
java·spring boot·neo4j
零雲2 小时前
java面试:可以讲一讲sychronized和ReentrantLock的异同点吗
java·开发语言·面试
没有bug.的程序员2 小时前
SQL 执行计划解析:从 EXPLAIN 到性能优化的完整指南
java·数据库·sql·性能优化·explain·执行计划
微笑尅乐3 小时前
神奇的位运算——力扣136.只出现一次的数字
java·算法·leetcode·职场和发展
Chan163 小时前
【 设计模式 | 结构型模式 代理模式 】
java·spring boot·后端·设计模式·intellij-idea
柯南二号3 小时前
【AI】【Java后端】RAG 实战示例:SpringBoot + 向量检索 + LLM 问答系统
java·人工智能·spring boot
Mr.Pascal3 小时前
后端直接返回错误信息的Map 和 抛出异常(异常机制)优劣势对比
java·springboot
zcychong3 小时前
如何让A、B、C三个线程按严格顺序执行(附十一种解)?
java·面试