苍穹外卖-day05

YangeIT大约 34 分钟苍穹外卖RedisSpringDataRedis过期时间整合Redis

苍穹外卖-day05

课程内容

  • Redis入门
  • Redis数据类型
  • Redis常用命令
  • 在Java中操作Redis
  • 店铺营业状态设置

功能实现🎯:营业状态设置

效果图:image-20221130223019209

1. Redis入门 🍐 🚩

1.0 Redis概述

Redis概述

image
image

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

key-value结构存储:

image-20221130173459174
image-20221130173459174

主要特点: 🍐

  • 基于内存存储,读写性能高
  • 适合存储热点数据(热点商品、资讯、新闻)
  • 企业应用广泛

Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS(每秒内查询次数) 。它存储的value类型比较丰富,也被称为结构化的NoSql数据库。

NoSql(Not Only SQL),不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。

关系型数据库(RDBMS):

  • Mysql 企业常用
  • Oracle 企业常用
  • DB2
  • SQLServer

非关系型数据库(NoSql):

  • Redis 企业常用
  • Mongo db 企业常用
  • MemCached

安装下载操作: 👇

1)在Windows中安装Redis(项目中使用)

Redis的Windows版属于绿色软件,直接解压即可使用,解压后目录结构如下:

image-20221130180657152

1.3 Redis服务启动与停止

以window版Redis进行演示:

  1. 服务启动命令,启动redis数据库
  2. 使用命令行客户端连接操作,cmd黑窗口
  3. 端口默认为6379,如果要修改密码或者端口,可以修改配置文件
  4. 为了方便操作redis,使用图形化客户端操作(类似navicat),

1.3.1 服务启动命令

# 启动exe  配置文件
redis-server.exe redis.windows.conf
image-20221130181950351

Redis服务默认端口号为 6379 ,通过快捷键Ctrl + C 即可停止Redis服务

当Redis服务启动成功后,可通过客户端进行连接。

总结

  1. Redis是一个基于 内存 的key-value结构非关系型数据库,读写性能高,适合缓存热点数据(热点商品、资讯、新闻),减少数据库查询次数,提高用户体验,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)

课堂作业

  1. Redis有哪些作用? 对比Mysql有哪些优势?🎤
  2. Redis最新的大版本是多少? https://redis.io/open in new window 🎤
  3. 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。
  • 应用场景: 适用于缓存、计数器、分布式锁等场景。常常用于存储简单的数据,如用户信息、配置信息、验证码、状态信息等。

总结

课堂作业

  1. Redis常用的5种数据类型有哪些? 其中字符串类型的应用场景有哪些?🎤
  2. Redis中的有序集合sorted的应用场景有哪些?

3. Redis常用命令 🚩

在线Redis指令练习网站open in new window 👈

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.cnopen in new window

代码操作

案例

🚩 练习指令字符串指令

  1. 存入key为name value为 xiaoming
  2. 存入key为age value为 20,然后再存入value为30,观察是否会覆盖
  3. 存入key为city value为beijing 过期时间为10s
  4. 存入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 中存储中文,默认读取不到中文,而是以十六进制的方式储存

⚠️ 中文乱码的解决方式--了解即可open in new window

总结

课堂作业

  1. Redis 中字符串类型常用命令有哪些?🎤
  2. 字符串类型常用于什么引用场景?

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 的所有字段和值
image-20210927113014567
image-20210927113014567

代码操作

作业

🚩 练习指令哈希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


总结

课堂作业

  1. Redis 中哈希hash操作命令有哪些?🎤
  2. Redis中的hash结构,常常用来存放什么?

3.3 列表 list 操作命令

列表 list 操作命令

列表 list 操作命令

Redis 列表是简单的字符串列表,按照插入顺序排序,常用命令:

先插入的在尾部,后插入的在头部

  • LPUSH key value1 [value2] 将一个或多个值插入到列表头部
  • LRANGE key start stop 获取列表指定范围内的元素
  • RPOP key 移除并获取列表最后一个元素
  • LLEN key 获取列表长度
  • BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超 时或发现可弹出元素为止
image-20210927113312384
image-20210927113312384

代码操作

案例

🚩 练习指令列表 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  

总结

课堂作业

  1. Redis 中列表 list 操作命令有哪些?🎤
  2. 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] 移除集合中一个或多个成员
image-20210927113632472
image-20210927113632472

代码操作

案例

根据图解完成指令

  1. 查询 set1集合和set2集合的交集

场景:可以获得共同的好友

  1. 查询 set1集合和set2集合的并集

场景:可以获得所有的好友人物

  1. 查询 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 # 删除元素

总结

课堂作业

  1. Redis 中set 操作命令有哪些?🎤
  2. 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 ...] 移除有序集合中的一个或多个成员
image-20210927114003383
image-20210927114003383

案例

🚩 练习指令有序集合 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这个元素移除

总结

课堂作业

  1. Redis 中sorted set 操作命令有哪些?🎤
  2. 有序集合的应用场景有哪些?

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

代码操作

案例

# 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 库中的数据量,也就是说这个命令的执行时间是随着库中的数据量增多呈正比的,数据量越大,执行时间越长。所以尽管这个命令的速度很快,但如果是一个数据量很大的库,还是会造成性能问题的。

总结

image
image
  • 外卖项目:

    • 字符串(String):
      • 应用场景: 存储用户的基本信息、订单信息等。例如,可以将用户的地址信息、订单号等存储在字符串中。
    • 哈希表(Hash):
      • 应用场景: 存储用户详细信息,如用户的个人资料。可以使用哈希表将用户ID作为键,用户信息作为字段存储。
    • 列表(List):
      • 应用场景: 订单队列,用于存储用户提交的订单,支持快速的订单插入和获取操作。
    • 集合(Set):
      • 应用场景: 存储用户的收藏夹或者喜好标签。可以使用集合存储用户喜欢的食物类型、餐馆标签等。
    • 有序集合(Sorted Set):
      • 应用场景: 排行榜功能,根据用户的订单金额或者积分排名。有序集合可以按照分数排序,方便实现排行榜功能。
  • 股票项目:

    • 字符串(String):
      • 应用场景: 开市,休市状态
    • 哈希表(Hash):
      • 应用场景: 存储股票的详细信息,如公司财报、市值等。每支股票可以作为一个哈希表。
    • 列表(List):
      • 应用场景: 存储股票交易日志,支持快速的插入和查询操作。
    • 集合(Set):
      • 应用场景: 存储用户自选股列表,确保每支股票在用户的自选列表中是唯一的。
    • 有序集合(Sorted Set):
      • 应用场景: 股票排名功能,根据股票的涨跌幅或其他指标进行排名。有序集合可以很方便地支持这样的功能。

课堂作业

  1. 导入课程资料中的dump.rdb文件
  • #停止redis服务
  • 然后进入redis的文件存放目录/var/lib/redis,把刚刚备份的dump.rdb文件替换该目录下的dump.rdb文件
  • #启动redis服务 到此,redis数据迁移完成
  1. 统一指令的引用场景有哪些?🎤
  2. 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。

代码操作

进入到sky-server模块

步骤

  1. 导入Spring Data Redis的maven坐标
  2. 配置Redis数据源
  3. 编写配置类,创建RedisTemplate对象
  4. 通过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();
    }
}

测试:

image-20221130205351403

说明RedisTemplate对象注入成功,并且通过该RedisTemplate对象获取操作5种数据类型相关对象。

上述环境搭建完毕后,接下来,我们就来具体对常见5种数据类型进行操作。

5. 店铺营业状态设置 🚩 🎯

前言

管理端原型open in new window

苍穹外卖-管理端接口open in new window

进到苍穹外卖后台,显示餐厅的营业状态,营业状态分为营业中打烊中

  1. 若当前餐厅处于营业状态,自动接收任何订单,客户可在小程序进行下单操作;
  2. 若当前餐厅处于打烊状态,不接受任何订单,客户便无法在小程序进行下单操作。
image-20221130212134915

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

image-20221130213550300

选择营业,设置餐厅为营业中状态

选择打烊,设置餐厅为打烊中状态

状态说明:

image-20221130213947179

代码步骤

核心步骤

  1. 在sky-server模块中,创建ShopController,定义setStatus设置营业状态---设置营业状态
  2. 定义创建ShopController定义getStatus接口查询营业状态方法---管理端查询营业状态
  3. 定义创建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();
    }
}

6. Swagger接口分组展示

Swagger接口分组展示

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

image-20221201181927458

接下来,我们要实现管理端和用户端接口进行区分。

代码操作

在WebMvcConfiguration.java中,分别扫描com.sky.controller.admincom.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;
    }














 




















 





如果想继续了解redis,后续后redis高级课程,当然也可以查看一篇文字了解redisopen in new window

课后作业

🚩 1. 重点完成上述的课堂作业

  1. 晚自习第一节课的前30分钟,总结完毕之后,每个同学先必须梳理今日知识点 (记得写不知道的,以及感恩三件事);整理好的笔记可以发给组长,组长交给班长,意在培养大家总结的能力)

  2. 晚自习第一节课的后30分钟开始练习(记住:程序员是代码堆起来的):

  3. 剩余的时间:预习第二天的知识,预习的时候一定要注意:

  • 预习不是学习,不要死看第二天的视频(很容易出现看了白看,为了看视频而看视频)
  • 预习看第二天的笔记,把笔记中标注重要的知识,可以找到预习视频,先看一遍,如果不懂的 ,记住做好标注。

面试题

  1. 什么是 Redis?简述它的优缺点?
  2. Redis 支持哪几种数据类型?
  3. Redis 官方为什么不提供 Windows 版本?
  4. 过期策略有什么应用场景?使用过期时间有什么注意事项?
  5. 一个字符串类型的值能存储最大容量是多少?
  6. Redis 如何做内存优化?