Redis 五大常用数据类型详解及 Java 客户端(RedisTemplate)操作实战

Redis 核心概念与 Spring Boot 整合实战

本文档详细记录了 Redis 的安装、核心概念、常用命令以及在 Spring Boot 项目中的整合与使用方式。


1. 环境安装与启动

1.1 安装 Redis (MacOS)

使用 Homebrew 进行安装:

bash 复制代码
brew install redis

1.2 启动服务

  • 临时启动 (终端关闭后服务停止):

    bash 复制代码
    redis-server
  • 后台启动 (推荐,支持开机自启):

    bash 复制代码
    brew services start redis

2. 核心概念

2.1 什么是 Redis?

Redis (Remote Dictionary Server) 是一个开源的、基于内存的非关系型数据库 (NoSQL)

  • 核心特点
    • 基于内存:读写速度极快,适合处理高并发请求。
    • 键值存储 :数据以 Key-Value 形式存储,Key 也就是字符串,Value 支持多种数据结构。
    • 应用场景:缓存(热点数据)、消息队列、分布式锁、排行榜等。

2.2 五大常用数据类型

Redis 的 Value 通常支持以下五种数据结构:

数据结构 英文名称 核心特点 典型应用场景
字符串 String 最基础类型,可存储字符串、数字,支持自增/自减。 缓存用户信息、计数器(阅读量)、分布式 Session、分布式锁。
哈希 Hash 键值对的集合(类似 Java 的 HashMap),适合存储对象。 存储对象详情(如用户:姓名、年龄、手机号)。
列表 List 有序字符串集合(双向链表),支持两端操作。 简单消息队列、最新动态列表(朋友圈)、任务排队。
集合 Set 无序且唯一的字符串集合,支持交集、并集运算。 去重(点赞用户)、共同好友、抽奖(随机获取)。
有序集合 ZSet 有序且唯一,每个元素关联一个 score (分数) 用于排序。 排行榜(游戏战力、热搜)、带权重的队列。

图 1:Redis 五种基本数据类型示意图


3. 常用命令详解

3.1 字符串 (String)

redis 复制代码
# 设置 key 的值
SET key value

# 获取 key 的值
GET key

# 设置 key 的值,并指定过期时间 (单位: 秒)
# 场景: 验证码、缓存数据
SETEX key seconds value

# 只有在 key 不存在时设置值 (Set If Not Exists)
# 场景: 分布式锁
SETNX key value

3.2 哈希 (Hash)

Hash 特别适合用于存储对象。

redis 复制代码
# 设置哈希表 key 中的字段 field 的值为 value
HSET key field value

# 获取哈希表 key 中指定字段 field 的值
HGET key field

# 删除哈希表 key 中的一个或多个字段
HDEL key field

# 获取哈希表中所有的字段名
HKEYS key

# 获取哈希表中所有的字段值
HVALS key

3.3 列表 (List)

简单的字符串列表,按照插入顺序排序。

redis 复制代码
# 将一个或多个值插入到列表头部 (左侧)
LPUSH key value1 [value2]

# 获取列表指定范围内的元素 (0 -1 表示获取所有)
LRANGE key start stop

# 移除并获取列表最后一个元素 (右侧弹出)
RPOP key

# 获取列表长度
LLEN key

# 移出并获取列表的最后一个元素,如果列表为空则阻塞等待直到超时
# 场景: 阻塞队列
BRPOP key1 [key2] timeout

3.4 集合 (Set)

无序集合,成员唯一。

redis 复制代码
# 向集合添加一个或多个成员
SADD key member1 [member2]

# 返回集合中的所有成员
SMEMBERS key

# 获取集合的成员数
SCARD key

# 返回给定所有集合的交集
SINTER key1 [key2]

# 返回所有给定集合的并集
SUNION key1 [key2]

# 移除集合中一个或多个成员
SREM key member1 [member2]

3.5 有序集合 (Sorted Set / ZSet)

不允许重复成员,通过 score 排序。

redis 复制代码
# 向有序集合添加成员,同时指定分数
ZADD key score1 member1 [score2 member2]

# 通过索引区间返回有序集合中指定区间内的成员
# WITHSCORES: 同时返回分数
ZRANGE key start stop [WITHSCORES]

# 对指定成员的分数加上增量 increment
ZINCRBY key increment member

# 移除有序集合中的一个或多个成员
ZREM key member [member ...]

3.6 通用命令

不区分数据类型,全局可用。

redis 复制代码
# 查找所有符合给定模式的 key (* 代表所有)
# 注意: 生产环境慎用,可能会阻塞服务器
KEYS pattern

# 检查给定 key 是否存在
EXISTS key

# 返回 key 所储存的值的类型
TYPE key

# 删除 key
DEL key

🔗 更多命令参考Redis 中文网


4. Spring Boot 整合 Redis

在 Java 开发中,我们通常使用 Spring Data Redis ,它对底层的 Jedis 或 Lettuce 进行了高度封装,提供了 RedisTemplate 来简化操作。

4.1 引入依赖

pom.xml 中添加 Starter 依赖。

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

4.2 配置数据源

application.ymlapplication.properties 中配置连接信息。

图 2:Redis 连接配置示例 (建议将敏感信息放在 dev 配置文件中)

yaml 复制代码
spring:
  redis:
    host: localhost
    port: 6379
    password: yourpassword # 如果没有密码则留空
    database: 0 # 指定数据库索引

4.3 配置 RedisTemplate (关键步骤)

默认的 RedisTemplate 使用 JDK 序列化,会导致 Redis 中存储的 Key 和 Value 出现乱码(二进制字符),不便于查看。我们需要配置序列化器。 value不进行序列化,因为value可能是多种不同的数据类型

图 3:未配置序列化器时,Redis 中的乱码现象

配置类实现:

java 复制代码
@Configuration
@Slf4j
public class RedisConfiguration {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        log.info("开始创建 Redis 模版对象...");
        RedisTemplate redisTemplate = new RedisTemplate();
        
        // 1. 设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 2. 设置序列化器 (解决乱码问题)
        // Key 使用 String 序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // Value 也使用 String 序列化器 (也可以使用 Jackson2JsonRedisSerializer 转 JSON)
        //redisTemplate.setValueSerializer(new StringRedisSerializer());
        
        return redisTemplate;
    }
}

图 4:Redis 配置类结构


5. 代码操作实战

通过单元测试演示 RedisTemplate 对五种数据类型的操作。

图 5:单元测试结构

5.1 操作字符串 (String)

java 复制代码
@Test
public void testString(){
    // opsForValue() 获取操作 String 类型的接口
    
    // 1. set: 设置值
    redisTemplate.opsForValue().set("city", "北京");
    
    // 2. get: 获取值
    Object city = redisTemplate.opsForValue().get("city");
    System.out.println(city);
    
    // 3. setex: 设置值并指定过期时间 (3分钟)
    redisTemplate.opsForValue().set("code", "1234", 3, TimeUnit.MINUTES);
    
    // 4. setnx: 如果 key 不存在才设置 (常用于分布式锁)
    redisTemplate.opsForValue().setIfAbsent("lock", 1);
    redisTemplate.opsForValue().setIfAbsent("lock", 2); // key 已存在,设置失败
}

5.2 操作哈希 (Hash)

java 复制代码
@Test
public void testHash(){
    // opsForHash() 获取操作 Hash 类型的接口
    HashOperations hashOperations = redisTemplate.opsForHash();
    
    // 1. hset: 存入字段
    hashOperations.put("user:100", "name", "tom");
    hashOperations.put("user:100", "age", "20");
    
    // 2. hget: 获取指定字段
    Object name = hashOperations.get("user:100", "name");
    System.out.println(name);
    
    // 3. hkeys: 获取所有 Key
    Set keys = hashOperations.keys("user:100");
    System.out.println(keys);
    
    // 4. hvals: 获取所有 Value
    List values = hashOperations.values("user:100");
    System.out.println(values);
    
    // 5. hdel: 删除字段
    hashOperations.delete("user:100", "age");
}

5.3 操作列表 (List)

java 复制代码
@Test
public void testList(){
    // opsForList() 获取操作 List 类型的接口
    ListOperations listOperations = redisTemplate.opsForList();
    
    // 1. lpush: 从左侧存入多个值
    listOperations.leftPushAll("mylist", "a", "b", "c");
    listOperations.leftPush("mylist", "d"); // 结果: d, a, b, c
    
    // 2. lrange: 获取范围内的元素 (0 到 -1 代表所有)
    List mylist = listOperations.range("mylist", 0, -1);
    System.out.println(mylist);
    
    // 3. rpop: 从右侧弹出一个元素
    listOperations.rightPop("mylist");
    
    // 4. llen: 获取列表长度
    Long size = listOperations.size("mylist");
    System.out.println(size);
}

5.4 操作集合 (Set)

java 复制代码
@Test
public void testSet(){
    // opsForSet() 获取操作 Set 类型的接口
    SetOperations setOperations = redisTemplate.opsForSet();
    
    // 1. sadd: 添加元素 (自动去重)
    setOperations.add("set1", "a", "b", "c", "d");
    setOperations.add("set2", "a", "b", "x", "y");
    
    // 2. smembers: 获取所有成员
    Set members = setOperations.members("set1");
    System.out.println(members);
    
    // 3. scard: 获取集合大小
    Long size = setOperations.size("set1");
    System.out.println(size);
    
    // 4. sinter: 求交集 (a, b)
    Set intersect = setOperations.intersect("set1", "set2");
    System.out.println(intersect);
    
    // 5. sunion: 求并集
    Set union = setOperations.union("set1", "set2");
    System.out.println(union);
    
    // 6. srem: 移除元素
    setOperations.remove("set1", "a", "b");
}

5.5 操作有序集合 (ZSet)

java 复制代码
@Test
public void testZset(){
    // opsForZSet() 获取操作 ZSet 类型的接口
    ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    
    // 1. zadd: 添加元素并指定分数
    zSetOperations.add("zset1", "a", 10);
    zSetOperations.add("zset1", "b", 12);
    zSetOperations.add("zset1", "c", 9);
    
    // 2. zrange: 获取所有元素 (默认按分数升序)
    Set zset1 = zSetOperations.range("zset1", 0, -1);
    System.out.println(zset1);
    
    // 3. zincrby: 增加指定元素的分数
    zSetOperations.incrementScore("zset1", "c", 10); // c 变为 19
    
    // 4. zrem: 移除元素
    zSetOperations.remove("zset1", "a", "b");
}

5.6 通用命令操作

java 复制代码
@Test
public void testCommon(){
    // 1. keys: 获取所有匹配的 key (生产环境慎用)
    Set keys = redisTemplate.keys("*");
    System.out.println(keys);
    
    // 2. hasKey: 判断 key 是否存在
    Boolean hasName = redisTemplate.hasKey("name");
    Boolean hasSet1 = redisTemplate.hasKey("set1");
    
    // 3. type: 获取 key 的类型
    for (Object key : keys) {
        DataType type = redisTemplate.type(key);
        System.out.println("Key: " + key + ", Type: " + type.name());
    }
    
    // 4. delete: 删除 key
    redisTemplate.delete("mylist");
}
相关推荐
huaqianzkh2 小时前
对应数据仓库、数据湖与湖仓一体三类场景开箱即用的工具清单
数据库
知识分享小能手2 小时前
Ubuntu入门学习教程,从入门到精通, Ubuntu 22.04中的进程管理详解(15)
linux·学习·ubuntu
0和1的舞者2 小时前
SpringAOP详解(二)
学习·spring·切面·代理·知识·springaop
iiiiii112 小时前
TD(λ),资格迹(Eligibility Traces)与时序差分学习的统一
人工智能·学习·机器学习·强化学习·rl
廋到被风吹走2 小时前
【Spring】Spring Cache 深度解析
java·后端·spring
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue个人博客系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
2501_946675643 小时前
Flutter与OpenHarmony打卡轮播图组件
java·javascript·flutter
走在路上的菜鸟3 小时前
Android学Flutter学习笔记 第一节 Android视角认知Flutter(View,intent,Async UI)
android·学习·flutter
独自破碎E3 小时前
Spring Boot 3.x和2.x版本相比有哪些区别与改进?
java·spring boot·后端