ChenZhen 搜索
首页 标签 归档 留言板 友链 ChatGPT 提示库 AI工具导航网 🚇开往 关于我

Redis的学习笔记

首先,确保 Redis 服务已经启动。可以使用以下命令进入 Redis 客户端(前提是 Redis 已经安装且正在运行): redis-cli Redis键 (key) 操作 keys * 查看当前库所有 key(匹配:keys *1)

ChenZhen 2022-10-06T15:18:12
cover

Redis的学习笔记

作者:ChenZhen
博客地址:https://www.chenzhen.space/
版权:本文为博主 ChenZhen 的原创文章,本文版权归作者所有,转载请附上原文出处链接及本声明。
如果对你有帮助,请给一个小小的star⭐


进入 Redis 客户端

首先,确保 Redis 服务已经启动。可以使用以下命令进入 Redis 客户端(前提是 Redis 已经安装且正在运行):

redis-cli

远程连接:如果 Redis 服务器在远程主机上,你可以使用 -h 和 -p 指定 IP 地址和端口:

redis-cli -h 192.168.1.100 -p 6379

如果 Redis 设置了密码,还需要加上 -a 参数:

redis-cli -h 192.168.1.100 -p 6379 -a yourpassword

1. Redis键 (key) 操作

  • keys * 查看当前库所有 key(匹配:keys *1

  • exists key 判断某个 key 是否存在

  • type key 查看你的 key 是什么类型

  • del key 删除指定的 key 数据

  • unlink key 根据 value 选择非阻塞删除,仅将 keys 从 keyspace 元数据中删除,真正的删除会在后续异步操作。

  • expire key 10 为给定的 key 设置 10 秒过期时间

  • ttl key 查看还有多少秒过期,-1 表示永不过期,-2 表示已过期

  • select 命令切换数据库

  • dbsize 查看当前数据库的 key 的数量

  • flushdb 清空当前库

  • flushall 清空全部库


2. Redis五大数据类型

2.1 Redis字符串 (String)

简介

String 是 Redis 最基本的类型,你可以理解为与 Memcached 一模一样的类型,一个 key 对应一个 value。String 类型是二进制安全的,意味着 Redis 的 string 可以包含任何数据,比如 jpg 图片或序列化的对象。一个 Redis 中字符串 value 最多可以是 512M。

常用命令

  • set <key> <value> [参数] 添加键值对

    • NX:当数据库中 key 不存在时,可以将 key-value 添加数据库
    • XX:当数据库中 key 存在时,可以将 key-value 添加数据库,与 NX 参数互斥
    • EX:key 的超时秒数
    • PX:key 的超时毫秒数,与 EX 互斥
  • get <key> 查询对应键值

  • append <key> <value> 将给定的 <value> 追加到原值的末尾

  • strlen <key> 获得值的长度

  • setnx <key> <value> 只有在 key 不存在时设置 key 的值

  • incr <key> 将 key 中储存的数字值加 1(只能对数字值操作,如果为空则新增值为 1)

  • decr <key> 将 key 中储存的数字值减 1(只能对数字值操作,如果为空则新增值为 -1)

  • incrby <key> <步长> / decrby <key> <步长> 将 key 中储存的数字值增减自定义步长。

  • mset <key1> <value1> <key2> <value2> ... 同时设置一个或多个 key-value 对

  • mget <key1> <key2> <key3> ... 同时获取一个或多个 value

  • msetnx <key1> <value1> <key2> <value2> ... 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在(原子性,有一个失败则都失败)

  • getrange <key> <起始位置> <结束位置> 获得值的范围,类似 Java 中的 substring,前包后包

  • setrange <key> <起始位置> <value><value> 覆写 <key> 所储存的字符串值,从 <起始位置> 开始(索引从 0 开始)。

  • setex <key> <过期时间> <value> 设置键值的同时,设置过期时间,单位秒。

  • getset <key> <value> 以新换旧,设置了新值的同时获得旧值。

1. Key 操作

  • keys *:查看当前数据库中所有的 key。
  • exists <key>:检查指定 key 是否存在,存在返回 1,否则返回 0
  • del <key>:删除指定的 key。
  • type <key>:查看指定 key 的类型。
  • expire <key> <seconds>:为指定 key 设置过期时间(单位:秒)。
  • ttl <key>:查看指定 key 剩余的过期时间(秒数),-1 表示永不过期,-2 表示已过期。

2. String 操作

  • set <key> <value>:为 key 设置字符串值。
  • get <key>:获取 key 对应的字符串值。
  • incr <key>:将 key 中储存的数字值加 1。
  • decr <key>:将 key 中储存的数字值减 1。
  • append <key> <value>:将给定的 value 追加到指定 key 的原值后。

3. List 操作

  • lpush <key> <value>:将 value 插入列表的左侧。
  • rpush <key> <value>:将 value 插入列表的右侧。
  • lpop <key>:移除并返回列表的左侧元素。
  • rpop <key>:移除并返回列表的右侧元素。
  • lrange <key> <start> <end>:获取列表指定范围内的元素。

4. Hash 操作

  • hset <key> <field> <value>:将 hash 表 key 中的字段 field 的值设为 value。
  • hget <key> <field>:获取 hash 表 key 中字段 field 对应的值。
  • hdel <key> <field>:删除 hash 表 key 中的指定字段。
  • hgetall <key>:获取 hash 表 key 中的所有字段和值。

5. Set 操作

  • sadd <key> <member>:向集合 key 中添加一个元素。
  • smembers <key>:获取集合 key 中的所有成员。
  • srem <key> <member>:移除集合中的一个或多个成员。

6. Sorted Set 操作

  • zadd <key> <score> <member>:向有序集合添加成员并设置分数。
  • zrange <key> <start> <stop>:根据分数范围获取有序集合中的成员。

7. 数据库操作

  • select <index>:选择 Redis 数据库,索引从 0 开始。
  • dbsize:查看当前数据库的 key 的数量。
  • flushdb:清空当前数据库。
  • flushall:清空所有数据库。

8. 退出 Redis 客户端

  • quit:退出 Redis 客户端。

这些命令可以帮助你完成大多数常见的 Redis 操作。

RedisTemplate 操作

RedisTemplate 是 Spring Data Redis 提供的高级 Redis 操作工具,支持多种数据结构,如字符串、哈希、列表、集合和有序集合等。以下是 RedisTemplate 的常用 API 操作:


1. 基本操作(String 类型)

@Autowired
private RedisTemplate<String, Object> redisTemplate;

// 设置值
redisTemplate.opsForValue().set("key", "value");

// 获取值
Object value = redisTemplate.opsForValue().get("key");

// 设置带过期时间的值
redisTemplate.opsForValue().set("key", "value", Duration.ofSeconds(60));

// 删除键
redisTemplate.delete("key");

// 判断键是否存在
Boolean exists = redisTemplate.hasKey("key");

// 设置新值并返回旧值
Object oldValue = redisTemplate.opsForValue().getAndSet("key", "newValue");

// 自增(整数)
Long increment = redisTemplate.opsForValue().increment("counter", 1);

// 自减(整数)
Long decrement = redisTemplate.opsForValue().decrement("counter", 1);

2. 哈希操作(Hash)

// 设置哈希字段值
redisTemplate.opsForHash().put("user:1001", "name", "张三");

// 获取哈希字段值
Object name = redisTemplate.opsForHash().get("user:1001", "name");

// 获取整个哈希表
Map<Object, Object> user = redisTemplate.opsForHash().entries("user:1001");

// 获取哈希表所有字段
Set<Object> keys = redisTemplate.opsForHash().keys("user:1001");

// 获取哈希表所有值
List<Object> values = redisTemplate.opsForHash().values("user:1001");

// 删除哈希字段
redisTemplate.opsForHash().delete("user:1001", "name");

// 判断哈希字段是否存在
Boolean exists = redisTemplate.opsForHash().hasKey("user:1001", "age");

// 增加哈希字段的数值
redisTemplate.opsForHash().increment("user:1001", "age", 1);

3. 列表操作(List)

// 左进(队列模式)
redisTemplate.opsForList().leftPush("myList", "A");

// 右进(栈模式)
redisTemplate.opsForList().rightPush("myList", "B");

// 获取列表长度
Long size = redisTemplate.opsForList().size("myList");

// 获取指定索引的值
Object item = redisTemplate.opsForList().index("myList", 0);

// 获取列表范围内的所有元素
List<Object> list = redisTemplate.opsForList().range("myList", 0, -1);

// 移除左端元素
Object leftPop = redisTemplate.opsForList().leftPop("myList");

// 移除右端元素
Object rightPop = redisTemplate.opsForList().rightPop("myList");

// 删除指定数量的值
redisTemplate.opsForList().remove("myList", 2, "A");

4. 集合操作(Set)

// 添加元素到集合
redisTemplate.opsForSet().add("mySet", "A", "B", "C");

// 获取集合所有元素
Set<Object> members = redisTemplate.opsForSet().members("mySet");

// 判断元素是否存在
Boolean isMember = redisTemplate.opsForSet().isMember("mySet", "A");

// 移除元素
redisTemplate.opsForSet().remove("mySet", "B");

// 获取集合大小
Long size = redisTemplate.opsForSet().size("mySet");

// 获取两个集合的交集
Set<Object> intersection = redisTemplate.opsForSet().intersect("set1", "set2");

// 获取两个集合的并集
Set<Object> union = redisTemplate.opsForSet().union("set1", "set2");

// 获取两个集合的差集
Set<Object> difference = redisTemplate.opsForSet().difference("set1", "set2");

5. 有序集合操作(ZSet)

// 添加元素到有序集合
redisTemplate.opsForZSet().add("myZSet", "A", 10);
redisTemplate.opsForZSet().add("myZSet", "B", 20);

// 获取集合中的所有元素
Set<Object> elements = redisTemplate.opsForZSet().range("myZSet", 0, -1);

// 获取带分数的集合元素
Set<ZSetOperations.TypedTuple<Object>> tuples = redisTemplate.opsForZSet().rangeWithScores("myZSet", 0, -1);

// 获取元素的排名
Long rank = redisTemplate.opsForZSet().rank("myZSet", "A");

// 增加元素的分数
redisTemplate.opsForZSet().incrementScore("myZSet", "A", 5);

// 删除元素
redisTemplate.opsForZSet().remove("myZSet", "B");

// 获取指定分数范围内的元素
Set<Object> rangeByScore = redisTemplate.opsForZSet().rangeByScore("myZSet", 10, 30);

6. 其他操作

// 设置键的过期时间
redisTemplate.expire("key", Duration.ofMinutes(5));

// 获取剩余存活时间(秒)
Long ttl = redisTemplate.getExpire("key");

// 清空所有 Redis 数据
redisTemplate.getConnectionFactory().getConnection().flushDb();

这些 RedisTemplate API 覆盖了 Redis 的主要数据结构操作,实际开发中可根据业务需求进行封装和优化。

当然可以 ✅ 下面是一篇完整的、结构清晰的博客文章,适合放在团队知识库、个人博客或掘金等平台上。 主题围绕「Redis 存取 Java 对象的正确与高效方式」,并结合你代码中出现的场景。


💡RedisTemplate 中存取 Java 对象的正确姿势(含 List 示例)

在 Java 开发中,我们经常会临时把一些对象、列表或缓存数据存入 Redis。 例如下面的场景:

// 临时放入 Redis
String cacheKey = StrUtil.format(FILE_UPLOAD_ERROR_KEY, id);
redisTemplate.opsForValue().set(cacheKey, cachedDataList);

但问题来了—— 当我们从 Redis 取出数据时,如何正确还原成原始对象类型? 本文将带你彻底搞清楚几种常见的序列化方式与推荐实践。


🧱 一、默认情况:JDK 序列化

Spring Boot 中的 RedisTemplate 默认使用:

JdkSerializationRedisSerializer

也就是说,它会把对象序列化成二进制字节数组,Redis 中看到的内容是乱码。

✅ 存入:

redisTemplate.opsForValue().set(cacheKey, cachedDataList);

✅ 取出:

@SuppressWarnings("unchecked")
List<ReconciliationDetailUpload> cachedList =
        (List<ReconciliationDetailUpload>) redisTemplate.opsForValue().get(cacheKey);

⚠️ 注意:

  • ReconciliationDetailUpload 必须实现 Serializable 接口
  • 序列化和反序列化的 RedisTemplate 必须一致
  • Redis 中无法直接查看可读内容

这种方式虽然简单,但可读性差跨语言不兼容,不太推荐用于业务数据缓存。


📘 二、推荐方式:JSON 序列化(Jackson)

更常见的方式是使用 JSON 存储对象。 在 Spring Boot 中可以通过配置 GenericJackson2JsonRedisSerializer

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(factory);

    GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();

    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(serializer);

    template.afterPropertiesSet();
    return template;
}

✅ 存入:

redisTemplate.opsForValue().set(cacheKey, cachedDataList);

✅ 取出:

List<ReconciliationDetailUpload> cachedList =
        (List<ReconciliationDetailUpload>) redisTemplate.opsForValue().get(cacheKey);

这样 Redis 中看到的是清晰的 JSON 格式,可直接查看。 Jackson 会自动保存类型信息(@class 字段),方便反序列化。


🧩 三、如果使用的是 StringRedisTemplate

有些项目只配置了 StringRedisTemplate,它只能操作字符串。 这时就需要手动将对象序列化为 JSON:

✅ 存入:

stringRedisTemplate.opsForValue().set(cacheKey, JSONUtil.toJsonStr(cachedDataList));

✅ 取出:

String json = stringRedisTemplate.opsForValue().get(cacheKey);
List<ReconciliationDetailUpload> cachedList =
        JSONUtil.toList(json, ReconciliationDetailUpload.class);

这里推荐使用 HutoolJSONUtil,API 简洁、类型安全。


⚙️ 四、三种方式对比

序列化方式可读性性能是否推荐说明
JDK 序列化❌ 无✅ 中等⚠️ 一般默认方式,二进制
Jackson JSON✅ 高✅ 中等✅ 推荐可读、跨语言兼容
Hutool JSON + StringRedisTemplate✅ 高✅ 快✅ 推荐简洁灵活

💡 五、实际项目推荐方案

结合性能、可读性、兼容性综合考虑,推荐使用:

// 写入
redisTemplate.opsForValue().set(cacheKey, JSONUtil.toJsonStr(cachedDataList));

// 读取
String json = (String) redisTemplate.opsForValue().get(cacheKey);
List<ReconciliationDetailUpload> cachedList =
        JSONUtil.toList(json, ReconciliationDetailUpload.class);

优点:

  • Redis 中可直接查看 JSON 内容;
  • 不依赖类型信息;
  • 与前端或其他语言兼容;
  • 一行即可反序列化。

🔍 六、常见问题汇总

问题原因解决方案
取出来是乱码使用了 JDK 序列化改为 JSON 序列化
反序列化报错对象结构变动或无序列化器使用 Jackson 或 Hutool JSON
数据为空Redis key 拼写不一致打印日志检查 key
JSON 转对象失败泛型类型不明确指定 List<T> 类型解析

✅ 七、总结

“Redis 存储对象的关键不在 Redis,而在于序列化。”

常见三种方式:

场景推荐方式
临时缓存Hutool JSON
系统内部结构体Jackson JSON
需要高性能序列化Fastjson2 / Kryo(可选)

一句话总结:

⚙️ 存之前想清楚怎么“还原”, 📦 选对序列化工具,Redis 就能存一切!


© 版权声明
😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗😚😙😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😏😒🙄😬🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵🤯🤠🥳😎🤓🧐😕😟🙁☹️😮😯😲😳🥺😦😧😨😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬