Redis:数据结构与基础操作(String、List、Hash、Set、Sorted Set) - 实践
一、数据结构与操作
(一)基本数据结构
1. 字符串(String)
String 是 Redis 中最基础、最常用的数据结构。它是二进制安全的,也就是说可以存储任意类型的数据,例如:
普通字符串
整数、浮点数
图片(Base64 编码后)
JSON / 序列化对象 / 二进制内容
(1)典型应用场景
①简单数据存储
适用于存储常规文本或对象的场景:
用户 session、token
图片地址 / 用户昵称等基础属性
存储序列化对象(相比 Hash 更节省内存)
相关命令:SET、GET
②计数器业务
Redis 对整数操作原子化,非常适合:
接口限流(统计用户单位时间请求数)
文章浏览量 PV
点赞次数计数
相关命令:INCR、DECR
③分布式锁(SETNX 原理版)
可通过 SETNX key value 实现简单锁(生产需改良,如 RedLock)。
(2)基本操作
| 操作 | 含义 |
|---|---|
SET key value | 设置 key 的值 |
GET key | 获取 key 的值 |
EXISTS key | 判断 key 是否存在 |
DEL key | 删除指定 key |
(3)批量操作
| 命令 | 含义 |
|---|---|
MSET key value [key value ...] | 批量设置键值对(批量写) |
MGET key1 [key2 ...] | 批量获取多个 key 的值(批量读) |
(4)数值操作(原子性)
| 命令 | 含义 |
|---|---|
INCR key | 值加 1 |
DECR key | 值减 1 |
INCRBY key increment | 增加指定整数 |
INCRBYFLOAT key increment | 增加浮点数 |
(5)设置过期时间
| 命令 | 含义 |
|---|---|
EXPIRE key seconds | 设置过期时间(秒) |
TTL key | 查询剩余生存时间 |
SETEX key seconds value | 设置值并设置过期时间 |
PSETEX key milliseconds value | 毫秒级过期时间 |
SETNX key value | 不存在时才设置(可用于锁) |
(6)String 常用命令(按功能分类)
设置/获取
SET key value
GET key
GETSET key value:设置新值并返回旧值
STRLEN key:返回字符串长度
追加、覆盖
APPEND key value:追加字符串
SETRANGE key offset value:从 offset 开始覆盖
范围和位图
GETRANGE key start end:获取子字符串
GETBIT key offset:获取某位的二进制值
SETBIT key offset value:修改某位的二进制值
批量操作
MSET key value [...]
MGET key1 [...]
(7)Java 中的 String 类型映射(Jedis / Spring Data Redis)
①Jedis 使用示例
基本 set/get
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("username", "xiaoman");
String name = jedis.get("username");
System.out.println(name);
数值操作(INCR / DECR)
Jedis jedis = new Jedis("localhost", 6379);
jedis.incr("count");
jedis.decr("count");
System.out.println(jedis.get("count"));
SETNX 分布式锁
/**
* 获取锁(SETNX)
*/
public boolean tryLock(Jedis jedis, String lockKey, String lockValue) {
Long result = jedis.setnx(lockKey, lockValue);
return result == 1; // 返回 1 代表成功获取锁
}
/**
* 释放锁
*/
public void unlock(Jedis jedis, String lockKey, String lockValue) {
String current = jedis.get(lockKey);
if (lockValue.equals(current)) {
jedis.del(lockKey);
}
}
说明:这是最基础的分布式锁实现,仅用于理解原理。
②Spring Data Redis 使用示例
基本 set/get
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 写入
stringRedisTemplate.opsForValue().set("token", "abc123");
// 读取
String token = stringRedisTemplate.opsForValue().get("token");
数值操作(increment/decrement)
// 自增
stringRedisTemplate.opsForValue().increment("count");
// 自减
stringRedisTemplate.opsForValue().decrement("count");
分布式锁(SETNX + 过期时间)
/**
* 获取分布式锁:setIfAbsent 相当于 SETNX
*/
public boolean tryLock(String key, String value, long expireSeconds) {
Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(
key, value, Duration.ofSeconds(expireSeconds)
);
return Boolean.TRUE.equals(success);
}
/**
* 释放锁(确保只释放自己的锁)
*/
public void unlock(String key, String value) {
String currentValue = stringRedisTemplate.opsForValue().get(key);
if (value.equals(currentValue)) {
stringRedisTemplate.delete(key);
}
}
2. 列表(List)
List 是 按插入顺序排序 的字符串列表,支持:
双端插入/弹出(栈/队列)
范围查询(LRANGE)
阻塞操作(BLPOP)
(1)核心特性
| 特性 | 说明 | 类似的数据结构 |
|---|---|---|
| 有序 | 元素按插入顺序排序 | 链表 |
| 可从两端插入/弹出 | LPUSH / RPUSH / LPOP / RPOP | 栈、队列、消息队列 |
| 支持范围查询 | LRANGE 速度快(O(n)) | 分页展示 |
(2)典型应用场景
① 消息流(Timeline)
如:微博最新动态
常用命令:LPUSH + LRANGE
② 队列(先进先出 FIFO)
异步任务队列
RPUSH(入队)+ LPOP(出队)
③ 栈(后进先出 LIFO)
浏览器前进后退
LPUSH(入栈)+ LPOP(出栈)
④ 阻塞队列(BLPOP/BRPOP)
可实现简单 MQ,消费者等待生产者。
(3)常用操作汇总
插入
| 命令 | 说明 |
|---|---|
LPUSH key v1 [v2...] | 从左侧插入 |
RPUSH key v1 [v2...] | 从右侧插入 |
LPUSHX key v | 列表存在才左插 |
RPUSHX key v | 列表存在才右插 |
删除 / 弹出
| 命令 | 说明 |
|---|---|
LPOP key | 左侧弹出 |
RPOP key | 右侧弹出 |
LREM key count value | 删除 count 个指定 value |
获取 / 查询
| 命令 | 说明 |
|---|---|
LRANGE key start stop | 获取区间元素,如:0 -1 获取全部 |
LINDEX key index | 按索引取值 |
LLEN key | 获取列表长度 |
修改 / 限制
| 命令 | 说明 |
|---|---|
LSET key index value | 修改指定位置的值 |
LTRIM key start stop | 保留某一段,其余删除 |
阻塞操作(适合消息队列)
| 命令 | 说明 |
|---|---|
BLPOP key timeout | 阻塞式 LPOP |
BRPOP key timeout | 阻塞式 RPOP |
BRPOPLPUSH source dest timeout | 阻塞式 RPOPLPUSH |
(4)Java 中操作 Redis List 的示例(Spring Data Redis + Lettuce)
配置 RedisTemplate:
@Autowired
private StringRedisTemplate redisTemplate;
插入元素(LPUSH / RPUSH)
// 左侧插入
redisTemplate.opsForList().leftPush("list1", "a");
// 右侧插入
redisTemplate.opsForList().rightPush("list1", "b");
// 批量插入
redisTemplate.opsForList().rightPushAll("list1", "c", "d", "e");
弹出元素(LPOP / RPOP)
String v1 = redisTemplate.opsForList().leftPop("list1");
String v2 = redisTemplate.opsForList().rightPop("list1");
查看区间元素(LRANGE)
List list = redisTemplate.opsForList().range("list1", 0, -1);
获取长度(LLEN)
Long len = redisTemplate.opsForList().size("list1");
获取某一个索引的值(LINDEX)
String value = redisTemplate.opsForList().index("list1", 2);
设置某一位置的值(LSET)
redisTemplate.opsForList().set("list1", 1, "newValue");
删除指定元素(LREM)
redisTemplate.opsForList().remove("list1", 2, "a");
// 删除2个"a"
保留指定区间(LTRIM)
redisTemplate.opsForList().trim("list1", 0, 10);
// 只保留前11个元素
阻塞式弹出(BLPOP / BRPOP)
// 等待 5 秒,直到有元素可取
String v = redisTemplate.opsForList().leftPop("queue", 5, TimeUnit.SECONDS);
适合做消费者。
(5)生产环境 List
用 List 实现简单队列
生产者:RPUSH
消费者:BLPOP(阻塞)
不推荐用 List 做无限长度队列
建议配合 LTRIM 控制长度:
redisTemplate.opsForList().rightPush("feed", "item");
redisTemplate.opsForList().trim("feed", 0, 999); // 控制列表最多 1000 条
3. 哈希(Hash)
Redis Hash 是一个 field → value 的映射表,非常适合存储对象,支持对对象字段进行独立修改,而不需要整个对象序列化后再存一次。
(1)Hash 的典型应用场景
对象存储
非常适合保存结构化对象,例如:
用户信息
商品信息
文章信息
配置项信息
示例结构:
user:1001
├── name → xiaoman
├── age → 18
└── city → beijing
相关命令:
HSET / HMSET(设置字段)
HGET / HMGET(获取字段)
HDEL(删除字段)
HGETALL(获取整个对象)
购物车
key = cart:userId
field = 商品ID
value = 数量或 JSON 信息
常用命令:
添加商品:HSET
数量+1:HINCRBY
删除商品:HDEL
商品总数:HLEN
获取全部商品:HGETALL
(2)基本操作:
| 命令 | 说明 |
|---|---|
HSET key field value | 设置某个字段值(覆盖) |
HMSET key field1 value1 ... | 设置多个字段(Redis 4.0 后建议使用 HSET 多参数形式) |
HGET key field | 获取某字段 |
HMGET key f1 f2 ... | 获取多个字段 |
HGETALL key | 获取所有字段和值 |
HDEL key f1 [f2 …] | 删除一个或多个字段 |
HEXISTS key field | 判断字段是否存在 |
HLEN key | 字段数量 |
HKEYS key | 获取所有 field |
HVALS key | 获取所有 value |
HINCRBY key field n | 对整数字段加 n |
HINCRBYFLOAT key field n | 对浮点字段加 n |
HSETNX key field value | 字段不存在时设置 |
HSCAN key cursor [MATCH pattern] [COUNT n] | 遍历大哈希表(分页迭代) |
(3)Hash 操作汇总
写字段
HSET key field value
HSET key field1 value1 field2 value2 ...(Redis 4.0+ 推荐)
HSETNX key field value
HINCRBY key field increment
HINCRBYFLOAT key field increment
读字段
HGET key field
HMGET key field1 field2 ...
HGETALL key
HKEYS key
HVALS key
HLEN key
删字段
HDEL key field1 [field2 ...]
遍历
HSCAN key cursor MATCH xx COUNT n
(4)Hash 使用注意事项
不要把特别大的对象放在一个 Hash
例如包含 10 万字段,这会:
HGETALL 非常慢
集群模式下扩容不均衡
HSCAN 复杂度变大
Hash 一个字段的值不能超过 512MB
Hash 适合结构化数据,不适合 JSON 长文本
如果 JSON 只是单值存储,推荐用 String。
(5)Java(Spring Data Redis + Lettuce)操作 Hash 示例
假设已注入:
@Autowired
private StringRedisTemplate redisTemplate;
添加 / 修改字段(HSET)
redisTemplate.opsForHash().put("user:1001", "name", "xiaoman");
redisTemplate.opsForHash().put("user:1001", "age", "18");
批量添加字段(HMSET → 使用 putAll)
Map data = new HashMap<>();
data.put("name", "xiaoman");
data.put("city", "beijing");
redisTemplate.opsForHash().putAll("user:1001", data);
获取字段(HGET)
String name = (String) redisTemplate.opsForHash().get("user:1001", "name");
获取多个字段(HMGET)
List

浙公网安备 33010602011771号