Redis 作为后端开发必学的缓存神器,非常有学习的必要,相信你看完一定有收获~~

在项目开发中,性能优化是绕不开的话题。而解决性能问题最常用的手段,就是加缓存。今天就来聊聊缓存界的扛把子 ------Redis,看看它到底有多好用,以及怎么上手。
一、Redis 到底是个啥
1. 先搞懂 Redis 是啥
Redis 是用 C 语言写的一款高性能键值对数据库,最牛的地方是数据存在内存里,所以读写速度快到飞起。官方说每秒能处理 10 万 + 的查询,这速度比传统数据库快太多了。
现在互联网项目里,Redis 几乎是标配的存储中间件。它的主要特点:
- 数据存在内存,读写性能超强
- 特别适合存热点数据(比如热门商品、新闻资讯)
- 企业里用得非常多
Redis 默认端口是 6379,记一下,后面经常会用到。
官网在这里:redis.io,中文网:www.redis.net.cn/
这里插一嘴数据库分类:
关系型数据库(RDBMS):像 MySQL、Oracle 这些,数据存在表里,靠主键外键维护关系,优点是稳定安全
非关系型数据库(NoSql):不止 SQL 的意思,存储方式灵活,性能好。除了 Redis,还有 MongoDB(存文档的)、MemCached(也是缓存)
2. 安装 Redis
如果自己想装,用 docker 最方便,一条命令搞定:
css
docker run -d --name redis --restart=always -p 6379:6379 redis --requirepass "123456"
这条命令会创建并启动 Redis 容器,要是本地没有镜像,会自动下载。
查看是否启动成功,看容器状态就行。

3. 用什么工具操作 Redis
总不能每次都进容器里敲命令吧?可以用图形化客户端,Another-Redis-Desktop-Manager,装上就能用。
安装好启动后,填好连接信息(地址、端口、密码),连上就能看到 Redis 里存的数据了,操作起来很方便。

4. 小结一下
Redis 就是个键值对数据库,数据放内存里,速度快,适合存热点数据。
数据库分关系型和非关系型,Redis 属于后者。
端口 6379 要记住。
启动关闭用 docker 命令:docker stop redis(关闭)、docker start redis(启动)
二、Redis 常用命令
Redis 存的是 key-value 结构,key 是字符串,value 有 5 种常用类型:字符串(string)、哈希(hash)、列表(list)、无序集合(set)、有序集合(zset)。
命令可以查 Redis 中文网,这里说常用的。
1. 操作 string 类型
string 是最基础的类型,常用命令:
命令 | 说明 |
---|---|
SET key value | 给 key 设值,要是 key 已经有值,就覆盖掉 |
GET key | 取 key 的值 |
SETEX key seconds value | 设值的同时,给 key 设个过期时间(秒) |
SETNX key value | 只有 key 不存在的时候才设值(分布式锁就靠这玩意) |
还有个通用命令 del key,不管啥类型,想删 key 就用它。
2. 操作 hash 类型
hash 就像 Java 里的 HashMap,适合存对象。比如存用户信息,key 是用户 id,里面的 field 是 name、age 这些。
常用命令:
命令 | 说明 |
---|---|
HSET key field value | 给 hash 里的 field 设值 |
HGET key field | 取 hash 里某个 field 的值 |
HKEYS key | 取 hash 里所有的 field |
HVALS key | 取 hash 里所有的值 |
HDEL key field | 删 hash 里的某个 field |
3. 操作 list 类型
list 类似 LinkedList,是个双向链表,有序,元素能重复。

常用命令:
命令 | 说明 |
---|---|
LPUSH key value1 [value2...] | 从左边往列表里加元素,返回列表长度 |
RPOP key | 从右边移除并返回最后一个元素 |
LRANGE key start stop | 取列表里指定范围的元素 |
LLEN key | 看列表有多少个元素 |
4. 操作 set 类型
set 类似 HashSet,无序,元素不能重复,查找快,还能做交集、并集这些操作。
常用命令:
命令 | 说明 |
---|---|
SADD key member1 [member2...] | 往集合里加元素 |
SMEMBERS key | 取集合里所有元素 |
SCARD key | 看集合有多少个元素 |
SINTER key1 [key2] | 取两个集合的交集 |
SUNION key1 [key2] | 取两个集合的并集 |
5. 操作 zset 类型
zset 是有序的 set,每个元素有个分数(score),按分数排序,适合做排行榜。
常用命令:
命令 | 说明 |
---|---|
ZADD key score1 member1 [score2 member2...] | 往有序集合里加元素,指定分数 |
ZRANGE key start stop [WITHSCORES] | 按索引范围取元素,加 WITHSCORES 能看到分数 |
ZINCRBY key increment member | 给某个元素的分数加增量 |
ZREM key member... | 从有序集合里删元素 |
6. 通用命令
不管啥类型都能用的命令:
命令 | 说明 |
---|---|
KEYS pattern | 找符合模式的 key,* 代表任意字符,? 代表一个字符 |
EXISTS key | 看看 key 存不存在 |
TYPE key | 看看 key 的值是啥类型 |
DEL key | 删 key,不管啥类型都能删 |
7. 小结一下
Redis 存的是键值对,key 是字符串,value 有 5 种类型:
- string:字符串,最基础的
- hash:哈希表,适合存对象
- list:链表,适合做队列
- set:无序集合,适合去重、做集合运算
- zset:有序集合,适合做排行榜
记几个常用操作就行,用的时候查文档也来得及。
三、SpringDataRedis
Java 项目里怎么操作 Redis 呢?就像用 JDBC 操作 MySQL 一样,得用 Redis 的 Java 客户端。常用的有 Jedis、Lettuce,而 Spring 给我们封装了 SpringDataRedis,用起来更方便,尤其是在 Spring Boot 项目里。
1. 简单介绍
Spring Data Redis 是 Spring 家族的一员,封装了底层的 Redis 客户端,配置一下就能用。
Spring Boot 里有对应的 starter,maven 依赖长这样(咱们项目的 common 模块里已经有了,直接用):
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
里面有个 RedisTemplate 类,特别好用,把各种操作分类了:
- 操作 string:redisTemplate.opsForValue ()
- 操作 hash:redisTemplate.opsForHash ()
- 操作 set:redisTemplate.opsForSet ()
- 操作 zset:redisTemplate.opsForZSet ()
- 操作 list:redisTemplate.opsForList ()
- 通用操作:直接用 redisTemplate
2. 准备环境
在 zzyl-admin 模块的 pom.xml 里加个单元测试的依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
然后在 com.zzyl.redis 包里建个测试类,注入 RedisTemplate:
kotlin
package com.zzyl.redis;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Test
public void test() {
System.out.println(redisTemplate);
}
}
3. 常用操作示例
csharp
/**
* 操作字符串
*/
@Test
public void testString() {
// 普通设值
redisTemplate.opsForValue().set("name", "张三");
System.out.println(redisTemplate.opsForValue().get("name"));
// 设值并加过期时间(20秒)
redisTemplate.opsForValue().set("token", "123qweasd",20, TimeUnit.SECONDS);
System.out.println(redisTemplate.opsForValue().get("token"));
// setnx,key不存在才设值,返回true,否则false
System.out.println(redisTemplate.opsForValue().setIfAbsent("lock", "09876", 5, TimeUnit.MINUTES));
System.out.println(redisTemplate.opsForValue().setIfAbsent("lock", "34567", 5, TimeUnit.MINUTES));
}
/**
* 操作哈希
*/
@Test
public void testHash() {
// 存哈希数据,大key是user,小key是name和age
redisTemplate.opsForHash().put("user", "name", "张三");
redisTemplate.opsForHash().put("user", "age", "30");
// 取哈希里的某个值
System.out.println(redisTemplate.opsForHash().get("user", "name"));
// 取所有小key
Set<Object> keys = redisTemplate.opsForHash().keys("user");
System.out.println(keys);
// 取所有值
List<Object> values = redisTemplate.opsForHash().values("user");
System.out.println(values);
// 删某个小key
redisTemplate.opsForHash().delete("user", "age");
}
/**
* 操作列表
*/
@Test
public void testList() {
// 从左边加多个值,变成[a,b,c]
redisTemplate.opsForList().leftPushAll("mylist", "a", "b", "c");
// 再从左边加个d,变成[d,a,b,c]
redisTemplate.opsForList().leftPush("mylist", "d");
// 取列表里的数据
System.out.println(redisTemplate.opsForList().range("mylist", 0, -1));
// 从左边弹出一个元素
System.out.println(redisTemplate.opsForList().leftPop("mylist"));
// 看列表长度
System.out.println(redisTemplate.opsForList().size("mylist"));
}
/**
* 操作集合
*/
@Test
public void testSet() {
// 往两个集合里加元素
redisTemplate.opsForSet().add("myset1", "a", "b", "c", "d");
redisTemplate.opsForSet().add("myset2", "a", "b", "x", "y");
// 取集合所有元素
Set<String> members = redisTemplate.opsForSet().members("myset1");
System.out.println(members);
// 看集合大小
long size = redisTemplate.opsForSet().size("myset1");
System.out.println(size);
// 取交集
Set<String> intersection = redisTemplate.opsForSet().intersect("myset1", "myset2");
System.out.println("交集:" + intersection);
// 取并集
Set<String> union = redisTemplate.opsForSet().union("myset1", "myset2");
System.out.println("并集:" + union);
}
/**
* 操作有序集合
*/
@Test
public void testZset() {
// 加元素,指定分数
redisTemplate.opsForZSet().add("myzset", "a", 1);
redisTemplate.opsForZSet().add("myzset", "b", 10);
redisTemplate.opsForZSet().add("myzset", "c", 20);
// 取所有元素
Set<String> members = redisTemplate.opsForZSet().range("myzset", 0, -1);
System.out.println(members);
// 给a的分数加10
redisTemplate.opsForZSet().incrementScore("myzset", "a", 10);
// 删a和b
redisTemplate.opsForZSet().remove("myzset", "a", "b");
}
/**
* 通用命令
*/
@Test
public void testCommon() {
// 取所有key
Set<String> keys = redisTemplate.keys("*");
System.out.println(keys);
// 看key是否存在
Boolean isName = redisTemplate.hasKey("name");
System.out.println(isName);
// 看key的类型
DataType type = redisTemplate.type("myzset");
System.out.println(type.name());
// 删key
redisTemplate.delete("myzset");
}
4. 小结一下
Java 里用 SpringDataRedis 操作 Redis,步骤很简单:
- 加依赖(项目里已经有了)
- 注入 RedisTemplate 对象
- 用对应的方法操作不同类型的数据
记住各个类型对应的方法前缀:
- string:opsForValue()
- hash:opsForHash()
- list:opsForList()
- set:opsForSet()
- zset:opsForZSet()
四、若依框架里的缓存使用
咱们用的若依框架,就是用 Redis 做缓存的。
核心的配置在 zzyl-framework 模块的 com.zzyl.framework.config.RedisConfig 类里。这个类主要是开启缓存注解,还有配置对象的序列化和反序列化(就是把对象转成能存的格式,取的时候再转回来)。
还有个 com.zzyl.common.core.redis.RedisCache 类,封装了常用的 Redis 操作方法,开发的时候直接用这个类就行,很方便。

五、用缓存优化项目
缓存就是高速的临时存储,用好缓存能大大提高系统性能。

1. 哪些数据适合放缓存
- 经常被访问,但不怎么变的数据:像用户信息、系统配置、数据字典这些
- 热门内容:热门文章、视频、评论,访问量特别大的
- 临时数据:比如验证码,存内存里快,还能设过期时间自动删
- 小数据但访问频繁:哪怕数据不大,只要经常被查,放缓存里也能提高性能
总之,缓存不是万能的,但用好它,系统性能能上一个大台阶。