苍穹外卖-day05
苍穹外卖-day05
课程内容
- Redis入门
- Redis数据类型
- Redis常用命令
- 在Java中操作Redis
- 店铺营业状态设置
功能实现🎯:营业状态设置
效果图:
选择营业中,客户可在小程序端下单:

选择打烊中,客户无法在小程序端下单:

1. Redis入门 🍐 🚩
1.0 Redis概述
Redis概述

Redis是一个基于 内存 的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件。
key-value结构存储:

主要特点: 🍐
- 基于内存存储,读写性能高
- 适合存储热点数据(热点商品、资讯、新闻)
- 企业应用广泛
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS(每秒内查询次数) 。它存储的value类型比较丰富,也被称为结构化的NoSql数据库。
NoSql(Not Only SQL),不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。
关系型数据库(RDBMS):
- Mysql 企业常用
- Oracle 企业常用
- DB2
- SQLServer
非关系型数据库(NoSql):
- Redis 企业常用
- Mongo db 企业常用
- MemCached
Redis已经推出到7.0,我们一起来看一下各个版本的Redis都增加了哪些新特性。
Redis2.6(2012)
- ① 服务端支持Lua脚本。
- ② 去掉虚拟内存相关功能。
- ③ 放开对客户端连接数的硬编码限制。
- ④ 键的过期时间支持毫秒。
- ⑤ 从节点支持只读功能。
- ⑥ 两个新的位图命令:bitcount和bitop。
- ⑦ 增强了redis-benchmark的功能:支持定制化的压测,CSV输出等功能。
- ⑧ 基于浮点数自增命令:incrbyfloat和hincrbyfloat。
- ⑨ redis-cli可以使用–eval参数实现Lua脚本执行。
- ⑩ shutdown命令增强。
- ⑪ 重构了大量的核心代码,所有集群相关的代码都去掉了,cluster功能将会是3.0版本最大的亮点。
- ⑫ info可以按照section输出,并且添加了一些统计项
- ⑬ sort命令优化
Redis2.8(2013-11-23)
- ① 添加部分主从复制的功能,在一定程度上降低了由于网络问题,造成频繁全量复制生成RDB对系统造成的压力。
- ② 尝试性的支持IPv6.
- ③ 可以通过config set命令设置maxclients。
- ④ 可以用bind命令绑定多个IP地址。
- ⑤ Redis设置了明显的进程名,方便使用ps命令查看系统进程。
- ⑥ config rewrite命令可以将config set持久化到Redis配置文件中。
- ⑦ 发布订阅添加了pubsub。
- ⑧ Redis Sentinel第二版,相比于Redis2.6的Redis Sentinel,此版本已经变成生产可用。
Redis3.0(2015-04-01里程碑)
- ① Redis Cluster:Redis的官方分布式实现。
- ② 全新的embedded string对象编码结果,优化小对象内存访问,在特定的工作负载下载速度大幅 提升。
- ③ Iru算法大幅提升。
- ④ migrate连接缓存,大幅提升键迁移的速度。
- ⑤ migrate命令两个新的参数copy和replace。
- ⑥ 新的client pause命令,在指定时间内停止处理客户端请求。
- ⑦ bitcount命令性能提升。
- ⑧ cinfig set设置maxmemory时候可以设置不同的单位(之前只能是字节)。
- ⑨ Redis日志小做调整:日志中会反应当前实例的角色(master或者slave)。
- ⑩ incr命令性能提升。
Redis3.2(2016-05-06)
- ① 添加GEO相关功能。
- ② SDS在速度和节省空间上都做了优化。
- ③ 支持用upstart或者systemd管理Redis进程。
- ④ 新的List编码类型:quicklist。
- ⑤ 从节点读取过期数据保证一致性。
- ⑥ 添加了hstrlen命令。
- ⑦ 增强了debug命令,支持了更多的参数。
- ⑧ Lua脚本功能增强。
- ⑨ 添加了Lua Debugger。
- ⑩ config set 支持更多的配置参数。
- ⑪ 优化了Redis崩溃后的相关报告。
- ⑫ 新的RDB格式,但是仍然兼容旧的RDB。
- ⑬ 加速RDB的加载速度。
- ⑭ spop命令支持个数参数。
- ⑮ cluster nodes命令得到加速。
- ⑯ Jemalloc更新到4.0.3版本。
Redis4.0(2017-07-15)
- ① 提供了模块系统,方便第三方开发者拓展Redis的功能。
- ② PSYNC2.0:优化了之前版本中,主从节点切换必然引起全量复制的问题。
- ③ 提供了新的缓存剔除算法:LFU(Last Frequently Used),并对已有算法进行了优化。
- ④ 提供了非阻塞del和flushall/flushdb功能,有效解决删除了bigkey可能造成的Redis阻塞。
- ⑤ 提供了memory命令,实现对内存更为全面的监控统计。
- ⑥ 提供了交互数据库功能,实现Redis内部数据库的数据置换。
- ⑦ 提供了RDB-AOF混合持久化格式,充分利用了AOF和RDB各自优势。
- ⑧ Redis Cluster 兼容NAT和Docker。
Redis5.0(2018-10-18)
- ① 新的Stream数据类型。
- ② 新的Redis模块API:Timers and Cluster API。
- ③ RDB现在存储LFU和LRU信息。
- ④ 集群管理器从Ruby(redis-trib.rb)移植到C代码。可以在redis-cli中。查看 redis-cli —cluster help`了解更多信息。
- ⑤ 新sorted set命令:ZPOPMIN / MAX和阻塞变量。
- ⑥ 主动碎片整理V2。
- ⑦ 增强HyperLogLog实现。
- ⑧ 更好的内存统计报告。
- ⑨ 许多带有子命令的命令现在都有一个HELP子命令。
- ⑩ 客户经常连接和断开连接时性能更好。
- ⑪ 错误修复和改进。
- ⑫ Jemalloc升级到5.1版
Redis6.0(2020-08-27)
- ① 许多新的模块API。
- ② 更好过期算法。
- ③ SSL支持。
- ④ ACL支持。
- ⑤ 新的RESP3协议。
- ⑥ 客户端缓存。
- ⑦ 多线程I/O
- ⑧ 副本的无盘复制。
- ⑨ redis-benchmark支持和redis-cli改进。
- ⑩ Systemd 支持重写。
- ⑪ redis集群代理的发布(还不稳定,不建议生产使用)。
- ⑫ disque模块的发布
Redis7.0
- ① 新增Function自定义函数库,函数库支持持久化与可复制。
- ② Lua脚本(脚本本身代码)不再支持持久化和复制,仅对命令执行结果进行持久化和复制。
- ③ ACL支持对Pub/Sub channel的权限控制。
- ④ 支持Multi-Part AOF。
- ⑤ 支持Client-Eviction。
- ⑥ 支持Sharded-Pub/Sub。
- ⑦ 支持命令执行耗时直方图。
- ⑧ 支持子命令级别的性能统计。
- ⑨ Ziplist编码替换为Listpack编码。
- ⑩ 支持Global Replication Buffer
截止到目前,最新版本:7.2.3
Redis安装包分为windows版和Linux版:
- Windows版下载地址:https://github.com/microsoftarchive/redis/releases
- Linux版下载地址: https://download.redis.io/releases/
资料中已提供好的安装包:

详细步骤见下方 👇
安装下载操作: 👇
1)在Windows中安装Redis(项目中使用)
Redis的Windows版属于绿色软件,直接解压即可使用,解压后目录结构如下:

2)在Linux中安装Redis(简单了解)
在Linux系统安装Redis步骤:
- 将Redis安装包上传到Linux
- 解压安装包,命令:tar -zxvf redis-4.0.0.tar.gz -C /usr/local
- 安装Redis的依赖环境gcc,命令:yum install gcc-c++
- 进入/usr/local/redis-4.0.0,进行编译,命令:make
- 进入redis的src目录进行安装,命令:make install
安装后重点文件说明:
- /usr/local/redis-4.0.0/src/redis-server:Redis服务启动脚本
- /usr/local/redis-4.0.0/src/redis-cli:Redis客户端脚本
- /usr/local/redis-4.0.0/redis.conf:Redis配置文件
1.3 Redis服务启动与停止
以window版Redis进行演示:
- 服务启动命令,启动redis数据库
- 使用命令行客户端连接操作,cmd黑窗口
- 端口默认为6379,如果要修改密码或者端口,可以修改配置文件
- 为了方便操作redis,使用图形化客户端操作(类似navicat),
1.3.1 服务启动命令
# 启动exe 配置文件
redis-server.exe redis.windows.conf

Redis服务默认端口号为 6379 ,通过快捷键Ctrl + C 即可停止Redis服务
当Redis服务启动成功后,可通过客户端进行连接。
1.3.2 客户端连接命令
redis-cli.exe

通过redis-cli.exe命令默认连接的是本地的redis服务,并且使用默认6379端口。也可以通过指定如下参数连接:
- -h ip地址
- -p 端口号
- -a 密码(如果需要)
如果出现:NOAUTH Authentication required.
其字面意思是要进行权限认证
- 解决办法: 输入redis 密码
- 格式为 : auth 密码 // 123456为密码
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379>
1.3.3 修改Redis配置文件
设置Redis服务密码,修改redis.windows.conf
requirepass 123456
注意:
- 修改密码后需要重启Redis服务才能生效
- Redis配置文件中 # 表示注释
重启Redis后,再次连接Redis时,需加上密码,否则连接失败。
redis-cli.exe -h localhost -p 6379 -a 123456

此时,-h 和 -p 参数可省略不写。
简单实用
1.3.4 Redis客户端图形工具默认提供的客户端连接工具界面不太友好,同时操作也较为麻烦,接下来,引入一个Redis客户端图形工具。
在当天资料中已提供安装包,直接安装即可。

安装完毕后,直接双击启动
新建连接

连接成功

总结
- Redis是一个基于 内存 的key-value结构非关系型数据库,读写性能高,适合缓存热点数据(热点商品、资讯、新闻),减少数据库查询次数,提高用户体验,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)
课堂作业
- Redis有哪些作用? 对比Mysql有哪些优势?🎤
- Redis最新的大版本是多少? https://redis.io/ 🎤
- RedisWindow版本启动后,能不能关闭黑窗口?
2. Redis数据类型 🍐 ❤️ 🚩
Redis数据类型
Redis存储的是key-value结构的数据,其中key是字符串类型,value支持多种类型的数据结构,如 字符串(strings),散列(hashes), 列表(lists),集合(sets),有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。
5种常用的数据类型
- 字符串(string):普通字符串,Redis中最简单的数据类型
- 哈希(hash):也叫散列,类似于Java中的HashMap结构
- 列表(list):按照插入顺序排序,可以有重复元素,类似于Java中的LinkedList
- 集合(set):无序集合,没有重复元素,类似于Java中的HashSet
- 有序集合(sorted set/zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素

应用场景:
字符串(String):
- 结构特点: 简单的键值对结构,存储的是二进制安全的字符串,最大可以存储 512MB。
- 应用场景: 适用于缓存、计数器、分布式锁等场景。常常用于存储简单的数据,如用户信息、配置信息、验证码、状态信息等。
哈希表(Hash):
- 结构特点: 内部是一个键值对集合,可以理解为一个小的对象或者字典。
- 应用场景: 适用于存储对象的属性,特别是对象的字段较多时。例如,存储用户信息、商品信息等。
列表(List):
结构特点: 有序的字符串链表,支持从两端添加或弹出元素。 应用场景: 适用于实现队列、栈,记录操作日志,消息队列等。可以按照插入的顺序存储一系列元素,支持快速的插入和删除操作。
集合(Set):
- 结构特点: 无序的字符串集合,不允许重复元素。
- 应用场景: 适用于存储唯一性的元素,例如标签、关注列表等。提供了快速判断某个元素是否存在的能力。
有序集合(Sorted Set):
- 结构特点: 类似于集合,但每个元素都有一个相关的分数(score),用于排序。
- 应用场景: 适用于需要根据某个属性排序的情况,例如排行榜、时间线等。可以根据分数范围获取一批元素。
总结
课堂作业
- Redis常用的5种数据类型有哪些? 其中字符串类型的应用场景有哪些?🎤
- Redis中的有序集合sorted的应用场景有哪些?
3. Redis常用命令 🚩
3.1 字符串 string 操作命令
字符串 string 操作命令
Redis 中字符串类型常用命令:
- SET key value 设置指定 key 的值
- GET key 获取指定 key 的值
- SETEX key seconds value 设置指定 key 的值,并将 key 的过期时间设为 seconds 秒
- SETNX key value 只有在 key 不存在时设置 key 的值
更多命令可以参考 Redis 中文网:https://www.redis.net.cn
代码操作
案例
🚩 练习指令字符串指令
- 存入key为name value为 xiaoming
- 存入key为age value为 20,然后再存入value为30,观察是否会覆盖
- 存入key为city value为beijing 过期时间为10s
- 存入key为bookname,value为zhuxian,继续存入bookname值为fanrenxiuxianzhuan,如果bookname存在值,不存,如果不存在,存入。
点击查看案例指令
# 存入一个字符串
set name xiaoming
# 获取name
get name
# 存入一个age
set age 20
set age 30
# 获得age
get age #30 覆盖了
# 练习 SETEX key seconds value 设置指定 key 的值,并将 key 的过期时间设为 seconds 秒
# 设置存10s
setex city 10 beijing
# 等待10秒
get city #返回nil --->空
# 练习SETNX key value 只有在 key 不存在时设置 key 的值
setnx bookname zhuxian
setnx bookname fanrenxiuxianzhuan
get bookname # 返回zhuxian
## 注意不要传中文,返回类似这种
"\xe5\x87\xa1\xe4\xba\xba\xe4\xbf\xae\xe4\xbb\x99\xe8\xae\xb0"
# 在redis 中存储中文,默认读取不到中文,而是以十六进制的方式储存
总结
课堂作业
- Redis 中字符串类型常用命令有哪些?🎤
- 字符串类型常用于什么引用场景?
3.2 哈希 hash 操作命令
前言
哈希hash操作命令
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,常用命令:
- HSET key field value 将哈希表 key 中的字段 field 的值设为 value
- HGET key field 获取存储在哈希表中指定字段的值
- HDEL key field 删除存储在哈希表中的指定字段
- HKEYS key 获取哈希表中所有字段
- HVALS key 获取哈希表中所有值
- HGETALL key 获取在哈希表中指定 key 的所有字段和值

代码操作
作业
🚩 练习指令哈希hash操作命令
根据图解完成指令

点击查看案例指令
# 往key 为001 存入 hash键值对 2对
hset 001 name zhangsan
hset 001 age 23
hset 002 name lisi
hset 002 age 16
# 练习 HGET key field 获取存储在哈希表中指定字段的值
# 获取002中的 name的值
hget 002 name
# 练习 HDEL key field 删除存储在哈希表中的指定字段
# 删除 002 中的name
hdel 002 name
# 练习HKEYS key 获取哈希表中所有字段
hkeys 002
# 练习HVALS key 获取哈希表中所有值
HVALS 002
# 练习 HGETALL key 获取在哈希表中指定 key 的所有字段和值
HGETALL 001
总结
课堂作业
- Redis 中哈希hash操作命令有哪些?🎤
- Redis中的hash结构,常常用来存放什么?
3.3 列表 list 操作命令
列表 list 操作命令
列表 list 操作命令
Redis 列表是简单的字符串列表,按照插入顺序排序,常用命令:
先插入的在尾部,后插入的在头部
- LPUSH key value1 [value2] 将一个或多个值插入到列表头部
- LRANGE key start stop 获取列表指定范围内的元素
- RPOP key 移除并获取列表最后一个元素
- LLEN key 获取列表长度
- BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超 时或发现可弹出元素为止

代码操作
案例
🚩 练习指令列表 list 操作命令
根据图解完成指令

点击查看案例指令
# LPUSH key value1 [value2] 将一个或多个值插入到列表头部
LPUSH list1 a b c d
LPUSH list2 1 2 3 4
LPUSH list3 9 8 7 6
# LRANGE key start stop 获取列表指定范围内的元素
LRANGE list1 0 -1 # 查所有
# a最先插入,所以在尾部
# RPOP key 移除并获取列表最后一个元素
RPOP list1 # 返回a 当然a没有了
# LLEN key 获取列表长度
LLEN list1 # 3
# BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超 时或发现可弹出元素为止
BRPOP list1 10
总结
课堂作业
- Redis 中列表 list 操作命令有哪些?🎤
- Redis种List结构,应用场景是有哪些?
3.4 集合 set 操作命令
集合 set 操作命令
set 操作命令
Redis set 是 string 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据,常用命令:
- SADD key member1 [member2] 向集合添加一个或多个成员
- SMEMBERS key 返回集合中的所有成员
- SCARD key 获取集合的成员数
- SINTER key1 [key2] 返回给定所有集合的交集
- SUNION key1 [key2] 返回所有给定集合的并集
- SDIFF key1 [key2] 返回给定所有集合的差集
- SREM key member1 [member2] 移除集合中一个或多个成员

代码操作
案例
根据图解完成指令

- 查询 set1集合和set2集合的交集
场景:可以获得共同的好友
- 查询 set1集合和set2集合的并集
场景:可以获得所有的好友人物
- 查询 set1集合和set2集合的差集
场景:
点击查看代码
# SADD key member1 [member2] 向集合添加一个或多个成员
SADD set1 a b c
SADD set2 1 2 3
# SMEMBERS key 返回集合中的所有成员
SMEMBERS set1
# SCARD key 获取集合的成员数
SCARD set1
# SINTER key1 [key2] 返回给定所有集合的交集
SINTER set1 set2 # a 交集是a
# SUNION key1 [key2] 返回所有给定集合的并集
SUNION set1 set2 # a b c 2 3
# SDIFF key1 [key2] 返回给定所有集合的差集
SDIFF set1 set2 #注意顺序 2者相减
# SREM key member1 [member2] 移除集合中一个或多个成员
SREM set1 a b # 删除元素
总结
课堂作业
- Redis 中set 操作命令有哪些?🎤
- Redis 中 set结构类型,应用场景有哪些?🎤
3.5 有序集合 sorted set 操作命令
有序集合
Redis sorted set 有序集合是 string 类型元素的集合,且不允许重复的成员。每个元素都会关联一个 double 类型的分数(score) 。redis 正是通过分数 来为集合中的成员进行从小到大排序 。有序集合的成员是唯一的,但分数却可以重复。
sorted set 操作命令
- ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的 分数
- ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合中指定区间内的成员
- ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment
- ZREM key member [member ...] 移除有序集合中的一个或多个成员

案例
🚩 练习指令有序集合 sorted set 操作命令
根据图解完成指令

点击查看案例指令
# ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的 分数
zadd sset1 0.1 a 3.0 b 2.5 c
zadd sset2 9.9 p 8.8 w 2.0 q
# ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合中指定区间内的成员
ZRANGE sset1 0 -1 # 获得全部
ZRANGE sset1 0 -1 WITHSCORES # 分数也会显示
# ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment
ZINCRBY sset1 20 b #意味着b的分值改变了
# 可以查询下
ZRANGE sset1 0 -1 WITHSCORES
# ZREM key member [member ...] 移除有序集合中的一个或多个成员
ZREM sset1 b #将b这个元素移除
总结
课堂作业
- Redis 中sorted set 操作命令有哪些?🎤
- 有序集合的应用场景有哪些?
3.6 通用命令
通用命令
Redis 中的通用命令,主要是针对 key 进行操作的相关命令:
通用命令
- KEYS pattern 查找所有符合给定模式( pattern)的 key
- EXISTS key 检查给定 key 是否存在
- TYPE key 返回 key 所储存的值的类型
- TTL key 返回给定 key 的剩余生存时间(TTL, time to live),以秒为单位
- DEL key 该命令用于在 key 存在是删除 key
Redis中key的命名,用:分隔不同的层次|命名空间
- user:id12345:contact 表示user表的ID为id12345的记录的字段contact。(那这个key的值就是对应的字段的值了)
在RedisDesktopManager这款Redis可视化管理工具中,只有使用单个:分隔的key名称,层次看起来最舒服
导入4w7千条数据:

代码操作
案例
# KEYS pattern 查找所有符合给定模式( pattern)的 key
KEYS * #查询所有的key
# EXISTS key 检查给定 key 是否存在
EXISTS bookname
# TYPE key 返回 key 所储存的值的类型
TYPE bookname
# TTL key 返回给定 key 的剩余生存时间(TTL, time to live),以秒为单位
TTL bookname # -1表示一直存在
# DEL key 该命令用于在 key 存在是删除 key
DEL bookname
KEYS * #查询所有的key
点击查看案例指令

注意
keys 命令的时间复杂度是 O(N),N 是 redis 库中的数据量,也就是说这个命令的执行时间是随着库中的数据量增多呈正比的,数据量越大,执行时间越长。所以尽管这个命令的速度很快,但如果是一个数据量很大的库,还是会造成性能问题的。
总结

外卖项目:
- 字符串(String):
- 应用场景: 存储用户的基本信息、订单信息等。例如,可以将用户的地址信息、订单号等存储在字符串中。
- 哈希表(Hash):
- 应用场景: 存储用户详细信息,如用户的个人资料。可以使用哈希表将用户ID作为键,用户信息作为字段存储。
- 列表(List):
- 应用场景: 订单队列,用于存储用户提交的订单,支持快速的订单插入和获取操作。
- 集合(Set):
- 应用场景: 存储用户的收藏夹或者喜好标签。可以使用集合存储用户喜欢的食物类型、餐馆标签等。
- 有序集合(Sorted Set):
- 应用场景: 排行榜功能,根据用户的订单金额或者积分排名。有序集合可以按照分数排序,方便实现排行榜功能。
- 字符串(String):
股票项目:
- 字符串(String):
- 应用场景: 开市,休市状态
- 哈希表(Hash):
- 应用场景: 存储股票的详细信息,如公司财报、市值等。每支股票可以作为一个哈希表。
- 列表(List):
- 应用场景: 存储股票交易日志,支持快速的插入和查询操作。
- 集合(Set):
- 应用场景: 存储用户自选股列表,确保每支股票在用户的自选列表中是唯一的。
- 有序集合(Sorted Set):
- 应用场景: 股票排名功能,根据股票的涨跌幅或其他指标进行排名。有序集合可以很方便地支持这样的功能。
- 字符串(String):
课堂作业
- 导入课程资料中的dump.rdb文件
- #停止redis服务
- 然后进入redis的文件存放目录/var/lib/redis,把刚刚备份的dump.rdb文件替换该目录下的dump.rdb文件
- #启动redis服务 到此,redis数据迁移完成
- 统一指令的引用场景有哪些?🎤
- redis中存入了商品shop 用户user的信息,如何快速的查询含有商品的信息
4.在Java中操作Redis 🍐 ❤️ 🚩
在Java中操作Redis
前面我们讲解了Redis的常用命令,这些命令是我们操作Redis的基础,那么我们在java程序中应该如何操作Redis呢?这就需要使用Redis的Java客户端,就如同我们使用JDBC操作MySQL数据库一样。
Redis 的 Java 客户端很多,常用的几种:
- Jedis
- Lettuce
- Spring Data Redis 简单实用
Spring 对 Redis 客户端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-boot-starter-data-redis。
Spring Data Redis是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
网址:https://spring.io/projects/spring-data-redis

Spring Data Redis中提供了一个高度封装的类RedisTemplate ,对相关api进行了归类封装,将同一类型操作封装为operation接口,
具体分类如下:
- ValueOperations:string数据操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:hash类型的数据操作
- ListOperations:list类型的数据操作
代码操作
进入到sky-server模块
步骤
- 导入Spring Data Redis的maven坐标
- 配置Redis数据源
- 编写配置类,创建RedisTemplate对象
- 通过RedisTemplate对象操作Redis
1). 导入Spring Data Redis的maven坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2). 配置Redis数据源
在application-dev.yml中添加
sky:
redis:
host: localhost
port: 6379
password: 123456
database: 10
解释说明:
database:指定使用Redis的哪个数据库,Redis服务启动后默认有16个数据库,编号分别是从0到15。 可以通过修改Redis配置文件来指定数据库的数量。
在application.yml中添加读取application-dev.yml中的相关Redis配置
spring:
profiles:
active: dev
redis:
host: ${sky.redis.host}
port: ${sky.redis.port}
password: ${sky.redis.password}
database: ${sky.redis.database}
3). 编写配置类,创建RedisTemplate对象
package com.sky.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@Slf4j
public class RedisConfiguration {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
log.info("开始创建redis模板对象...");
RedisTemplate redisTemplate = new RedisTemplate();
//设置redis的连接工厂对象
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置redis key的序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
解释说明:
当前配置类不是必须的,因为 Spring Boot 框架会自动装配 RedisTemplate 对象,但是默认的key序列化器为
JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别,故设置为
StringRedisSerializer序列化器。
4). 通过RedisTemplate对象操作Redis
在test下新建测试类
package com.sky.test;
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.*;
@SpringBootTest
public class SpringDataRedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testRedisTemplate(){
System.out.println(redisTemplate);
//string数据操作
ValueOperations valueOperations = redisTemplate.opsForValue();
//hash类型的数据操作
HashOperations hashOperations = redisTemplate.opsForHash();
//list类型的数据操作
ListOperations listOperations = redisTemplate.opsForList();
//set类型数据操作
SetOperations setOperations = redisTemplate.opsForSet();
//zset类型数据操作
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
}
}
测试:

说明RedisTemplate对象注入成功,并且通过该RedisTemplate对象获取操作5种数据类型相关对象。
上述环境搭建完毕后,接下来,我们就来具体对常见5种数据类型进行操作。
1). 操作字符串类型数据
/**
* 操作字符串类型的数据
*/
@Test
public void testString(){
// set get setex setnx
redisTemplate.opsForValue().set("name","小明");
String city = (String) redisTemplate.opsForValue().get("name");
System.out.println(city);
// 过期时间
redisTemplate.opsForValue().set("code","1234",3, TimeUnit.MINUTES);
// 存入前判断
redisTemplate.opsForValue().setIfAbsent("lock","1");
redisTemplate.opsForValue().setIfAbsent("lock","2");
}
2). 操作哈希类型数据
/**
* 操作哈希类型的数据
*/
@Test
public void testHash(){
//hset hget hdel hkeys hvals
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put("100","name","tom");
hashOperations.put("100","age","20");
String name = (String) hashOperations.get("100", "name");
System.out.println(name);
Set keys = hashOperations.keys("100");
System.out.println(keys);
List values = hashOperations.values("100");
System.out.println(values);
hashOperations.delete("100","age");
}
3). 操作列表类型数据
/**
* 操作列表类型的数据
*/
@Test
public void testList(){
//lpush lrange rpop llen
ListOperations listOperations = redisTemplate.opsForList();
listOperations.leftPushAll("mylist","a","b","c");
listOperations.leftPush("mylist","d");
List mylist = listOperations.range("mylist", 0, -1);
System.out.println(mylist);
listOperations.rightPop("mylist");
Long size = listOperations.size("mylist");
System.out.println(size);
}
4). 操作集合类型数据
/**
* 操作集合类型的数据
*/
@Test
public void testSet(){
//sadd smembers scard sinter sunion srem
SetOperations setOperations = redisTemplate.opsForSet();
setOperations.add("set1","a","b","c","d");
setOperations.add("set2","a","b","x","y");
Set members = setOperations.members("set1");
System.out.println(members);
Long size = setOperations.size("set1");
System.out.println(size);
Set intersect = setOperations.intersect("set1", "set2");
System.out.println(intersect);
Set union = setOperations.union("set1", "set2");
System.out.println(union);
setOperations.remove("set1","a","b");
}
5). 操作有序集合类型数据
/**
* 操作有序集合类型的数据
*/
@Test
public void testZset(){
//zadd zrange zincrby zrem
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
zSetOperations.add("zset1","a",10);
zSetOperations.add("zset1","b",12);
zSetOperations.add("zset1","c",9);
Set zset1 = zSetOperations.range("zset1", 0, -1);
System.out.println(zset1);
zSetOperations.incrementScore("zset1","c",10);
zSetOperations.remove("zset1","a","b");
}
6). 通用命令操作
/**
* 通用命令操作
*/
@Test
public void testCommon(){
//keys exists type del
Set keys = redisTemplate.keys("*");
System.out.println(keys);
Boolean name = redisTemplate.hasKey("name");
Boolean set1 = redisTemplate.hasKey("set1");
for (Object key : keys) {
DataType type = redisTemplate.type(key);
System.out.println(type.name());
}
redisTemplate.delete("mylist");
}
Spring Boot 为我们自动配置了 RedisTemplate,而 RedisTemplate 使用的是 JdkSerializationRedisSerializer,这个对我们用 redis 图形化客户端很不直观,因为 JdkSerializationRedisSerializer 使用二进制形式储存数据,在此我们将自己配置 RedisTemplate 并定义 Serializer

在config包中配置
@Configuration
public class RedisCacheConfig {
/**
* 配置redisTemplate bean,⾃定义数据的序列化的⽅式
* @param redisConnectionFactory 连接redis的⼯⼚,底层有
场景依赖启动时,⾃动加载
* @return
*/
@Bean
public RedisTemplate redisTemplate(@Autowired RedisConnectionFactory redisConnectionFactory){
//1.构建RedisTemplate模板对象
RedisTemplate<String, Object> template = newRedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//2.为不同的数据结构设置不同的序列化⽅案
//设置key序列化⽅式
template.setKeySerializer(new StringRedisSerializer());
//设置value序列化⽅式
template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
//设置hash中field字段序列化⽅式
template.setHashKeySerializer(new StringRedisSerializer());
//设置hash中value的序列化⽅式
template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
//5.初始化参数设置
template.afterPropertiesSet();
return template;
}
}
在存入一个json数据,观察可视化操作软件
思路:
- 创建一个对象或者从数据库中查出一个对象
- 引入fastjson包,将对象转成json字符
- 将json字符串存入到redis中,通过可视化软件观察value值
5. 店铺营业状态设置 🚩 🎯
前言
进到苍穹外卖后台,显示餐厅的营业状态,营业状态分为营业中和打烊中,
- 若当前餐厅处于营业状态,自动接收任何订单,客户可在小程序进行下单操作;
- 若当前餐厅处于打烊状态,不接受任何订单,客户便无法在小程序进行下单操作。

点击营业状态按钮时,弹出更改营业状态

选择营业,设置餐厅为营业中状态
选择打烊,设置餐厅为打烊中状态
状态说明:

虽然,可以通过一张表来存储营业状态数据,但整个表中只有一个字段,所以意义不大。
营业状态数据存储方式:基于Redis的字符串来进行存储

约定: 1表示营业 0表示打烊
根据上述原型图设计接口,共包含3个接口。
接口设计:
- 设置营业状态
- 管理端查询营业状态
- 用户端查询营业状态
注: 从技术层面分析,其实管理端和用户端查询营业状态时,可通过一个接口去实现即可。因为营业状态是一致的。但是,本项目约定:
- 管理端 发出的请求,统一使用/admin作为前缀。
- 用户端 发出的请求,统一使用/user作为前缀。
因为访问路径不一致,故分为两个接口实现。
1). 设置营业状态
见接口文档
2). 管理端营业状态
见接口文档
3). 用户端营业状态
见接口文档
代码步骤
核心步骤
- 在sky-server模块中,创建ShopController,定义setStatus设置营业状态---设置营业状态
- 定义创建ShopController定义getStatus接口查询营业状态方法---管理端查询营业状态
- 定义创建com.sky.controller.user包,并创建ShopController,定义getStatus接口查询营业状态方法---用户端查询营业状态
5.2.1 设置营业状态
在sky-server模块中,创建ShopController.java
根据接口定义创建ShopController的setStatus设置营业状态方法:
package com.sky.controller.admin;
@RestController("adminShopController")
@RequestMapping("/admin/shop")
@Api(tags = "店铺相关接口")
@Slf4j
public class ShopController {
public static final String KEY = "SHOP_STATUS";
@Autowired
private RedisTemplate redisTemplate;
/**
* 设置店铺的营业状态
* @param status
* @return
*/
@PutMapping("/{status}")
@ApiOperation("设置店铺的营业状态")
public Result setStatus(@PathVariable Integer status){
log.info("设置店铺的营业状态为:{}",status == 1 ? "营业中" : "打烊中");
redisTemplate.opsForValue().set(KEY,status);
return Result.success();
}
}
5.2.2 管理端查询营业状态
根据接口定义创建ShopController的getStatus查询营业状态方法:
/**
* 获取店铺的营业状态
* @return
*/
@GetMapping("/status")
@ApiOperation("获取店铺的营业状态")
public Result<Integer> getStatus(){
Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
log.info("获取到店铺的营业状态为:{}",status == 1 ? "营业中" : "打烊中");
return Result.success(status);
}
5.2.3 用户端查询营业状态
创建com.sky.controller.user包,在该包下创建ShopController.java
根据接口定义创建ShopController的getStatus查询营业状态方法:
package com.sky.controller.user;
@RestController("userShopController")
@RequestMapping("/user/shop")
@Api(tags = "店铺相关接口")
@Slf4j
public class ShopController {
public static final String KEY = "SHOP_STATUS";
@Autowired
private RedisTemplate redisTemplate;
/**
* 获取店铺的营业状态
* @return
*/
@GetMapping("/status")
@ApiOperation("获取店铺的营业状态")
public Result<Integer> getStatus(){
Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
log.info("获取到店铺的营业状态为:{}",status == 1 ? "营业中" : "打烊中");
return Result.success(status);
}
}
接口文档测试
启动服务: 访问http://localhost:8080/doc.html,打开店铺相关接口
注意: 使用admin用户登录重新获取token,防止token失效。
1️⃣ 设置营业状态:

点击发送

查看Idea控制台日志

查看Redis中数据

2️⃣ 管理端查询营业状态:

3️⃣ 用户端查询营业状态:

前后端联调测试
启动nginx,访问 http://localhost
进入后台,状态为营业中

点击营业状态设置,修改状态为打烊中

再次查看状态,状态已为打烊中

6. Swagger接口分组展示
Swagger接口分组展示
在上述接口文档测试中,管理端和用户端的接口放在一起,不方便区分。

接下来,我们要实现管理端和用户端接口进行区分。
代码操作
在WebMvcConfiguration.java中,分别扫描com.sky.controller.admin
和com.sky.controller.user
这两个包。
@Bean
public Docket docket1(){
log.info("准备生成接口文档...");
ApiInfo apiInfo = new ApiInfoBuilder()
.title("苍穹外卖项目接口文档")
.version("2.0")
.description("苍穹外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("管理端接口")
.apiInfo(apiInfo)
.select()
//指定生成接口需要扫描的包
.apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin"))
.paths(PathSelectors.any())
.build();
return docket;
}
@Bean
public Docket docket2(){
log.info("准备生成接口文档...");
ApiInfo apiInfo = new ApiInfoBuilder()
.title("苍穹外卖项目接口文档")
.version("2.0")
.description("苍穹外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("用户端接口")
.apiInfo(apiInfo)
.select()
//指定生成接口需要扫描的包
.apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))
.paths(PathSelectors.any())
.build();
return docket;
}
重启服务器,再次访问接口文档,可进行选择用户端接口或者管理端接口

代码提交 ⬆️
点击提交:

提交过程中,出现提示:

继续push:

推送成功:

如果想继续了解redis,后续后redis高级课程,当然也可以查看一篇文字了解redis
课后作业
🚩 1. 重点完成上述的课堂作业
晚自习第一节课的前30分钟,总结完毕之后,每个同学先必须梳理今日知识点 (记得写不知道的,以及感恩三件事);整理好的笔记可以发给组长,组长交给班长,意在培养大家总结的能力)
晚自习第一节课的后30分钟开始练习(记住:程序员是代码堆起来的):
- 先要把今天的所有案例或者课堂练习,如果没练完的,练完他
- 完成今日指数的Part02工作中的任务验证码登录功能 锻炼迁移能力👈
剩余的时间:预习第二天的知识,预习的时候一定要注意:
- 预习不是学习,不要死看第二天的视频(很容易出现看了白看,为了看视频而看视频)
- 预习看第二天的笔记,把笔记中标注重要的知识,可以找到预习视频,先看一遍,如果不懂的 ,记住做好标注。
面试题
- 什么是 Redis?简述它的优缺点?
- Redis 支持哪几种数据类型?
- Redis 官方为什么不提供 Windows 版本?
- 过期策略有什么应用场景?使用过期时间有什么注意事项?
- 一个字符串类型的值能存储最大容量是多少?
- Redis 如何做内存优化?