Bootstrap

《苍穹外卖》Day05部分知识点记录

一、Redis

1. Redis入门

  • 简介:Redis是一个基于内存key-value结构数据库。
  • 优点:基于内存存储,读写性能高。

                  适合存储热点数据(热点商品、资讯、新闻)

                  企业应用广泛

官网:https://redis.io

中文网:https://www.redis.net.cn/

双击运行。Ctrl + C:退出服务端。exit:退出客户端

  • 通过图形界面连接Redis客户端,要先运行Redis服务端

2. Redis数据类型

Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:

  • 字符串string:普通字符串,Redis中最简单的数据类型
  • 哈希hash:也叫散列,类似于Java中的HashMap结构
  • 列表list:按照插入顺序排序,可以有重复元素,类似于Java中的LinkedList
  • 集合set:无序集合,没有重复元素,类似于Java中的HashSet
  • 有序集合sorted set / zset:集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素

3. Redis常用命令

  • 字符串操作命令
命令作用
SET key value设置指定key的值
GET key获取指定key的值
SETEX key seconds value设置指定key的值,并将key的过期时间设为second秒(如验证码的过期时间)
SETNX key value只有在key不存在时设置key的值
  • 哈希操作命令

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。

命令作用
HSET key field value将哈希表key中的字段field的值设为value
HGET key field获取存储在哈希表中指定字段的值
HDEL key field删除存储在哈希表中的指定手段
HKEYS key获取哈希表中所有字段
HVALS key获取哈希表所有值
  • 列表操作命令

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

命令作用
LPUSH key value1 [value2]将一个或多个值插入到列表头部
LRANGE key start stop获取列表指定范围内的元素
RPOP key移除并获取列表最后一个元素
LLEN key获取列表长度
  • 集合操作命令

Redis set是string类型的无序集合。集合成员是唯一的,集合中不能出现重复的数据。

命令作用
SADD key member1 [member2]向集合添加一个或多个成员
SMEMBERS key返回集合中的所有成员
SCARD key获取集合的成员数
SINTER key1 [key2]返回给定所有集合的交集
SUNION key1 [key2]返回所有给定集合的并集
SREM key member1 [member2]删除集合中一个或多个成员
  • 有序集合操作命令

Redis有序集合是string类型元素的集合,且不允许有重复成员。每个元素都会关联一个double类型的分数。

命令作用
ZADD key score1 member1 [score2 member2]向有序集合添加一个或多个成员
ZRANGE key start stop[WITHSCORES]通过索引区间返回有序集合中指定区间内的成员
ZINCRBY key increment member有序集合中对指定成员的分数加上增量increment
ZREM key member [member...]移除有序集合中的一个或多个成员
  • 通用命令

Redis的通用命令是部分数据类型的,都可以使用的命令。

命令作用
KEYS pattern查找所有符合给定模式(pattern)的key
EXISTS key检查给定key是否存在
TYPE key返回key所存储的值的类型
DEL key该命令用于在key存在时删除key

4. 在Java中操作Redis

Redis的Java客户端:Jedis、Lettuce、Spring Data Redis

Spring Data Redis是Spring的一部分,对Redis底层开发包进行了高度封装。在Spring项目中,可以使用Spring Data Redis来简化操作。

Spring Data Redis的使用方式

  • 导入Spring Data Redis的maven坐标
    <!--        Redis-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
  • 配置Redis数据源(我没有使用密码,课程前面添加了密码的记得加上。在弹幕看到说要把password:改成auth:的,如果有报错就改一下)
    sky:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        host: localhost
        port: 3306
        database: sky_take_out
        username: root
        password: "123456"
      alioss:
        endpoint: oss-cn-guangzhou.aliyuncs.com
        access-key-id: LTAI5tN3GR9bpfgBucb9mFaW
        access-key-secret: fttgH1wrT1SZgM41njd74HlugAjBUM
        bucket-name: sky-take-out-lai
      redis:
        host: localhost
        port: 6379
        password:
        database: 0
    # application-dev.yml
    spring:
      profiles:
        active: dev
      main:
        allow-circular-references: true
      datasource:
        druid:
          driver-class-name: ${sky.datasource.driver-class-name}
          url: jdbc:mysql://${sky.datasource.host}:${sky.datasource.port}/${sky.datasource.database}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
          username: ${sky.datasource.username}
          password: ${sky.datasource.password}
      redis:
        host: ${sky.redis.host}
        port: ${sky.redis.port}
        password:
        database: ${sky.redis.database}
    # application.yml
  • 编写配置类,创建RedisTemplate对象。记得加上@Bean注解
    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;
        }
    }
  • 通过RedisTemplate对象操作Redis(测试完成之后记得把@SpringBootTest注解注释掉,以免影响效率)
package com.sky.test;

import java.util.concurrent.TimeUnit  // 我用的JDK22里面不知道怎么没有这个东西了
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.*;

import javax.management.timer.Timer;

@SpringBootTest
public class SpringDataRedisTest {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testRedisTemplate() {
        System.out.println(redisTemplate);
        ValueOperations valueOperations = redisTemplate.opsForValue();
        HashOperations hashOperations = redisTemplate.opsForHash();
        ListOperations listOperations = redisTemplate.opsForList();
        SetOperations setOperations = redisTemplate.opsForSet();
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    }


    /**
     * 操作字符串类型的数据
     */
    @Test
    public void testString() {
        // set get setex setnx
        redisTemplate.opsForValue().set("city", "北京");
        String city = (String) redisTemplate.opsForValue().get("city");
        System.out.println(city);
        redisTemplate.opsForValue().set("code", "1234", 3, TimeUnit.MINUTES);
        redisTemplate.opsForValue().setIfAbsent("lock", 1);
        redisTemplate.opsForValue().setIfAbsent("lock", 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");
    }

    /**
     * 操作列表类型的数据
     */
    @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);
    }

    /**
     * 操作集合类型的数据
     */
    @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");
    }

    /**
     * 操作有序集合类型的数据
     */
    @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");
    }

    /**
     * 通用命令操作
     */
    @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");
    }
}

二、更改接口文档扫描的包路径后出现knife4j异常

    /**
     * 通过knife4j生成接口文档
     * @return
     */
    @Bean
    public Docket docket2() {
        log.info("准备生成接口文档······");
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档")  // 标题
                .version("2.0")  // 版本号
                .description("苍穹外卖项目接口文档")  // 简介
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)  // 版本2
                .groupName("用户端接口")
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))  // 生成接口文档要扫描的包
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

解决:更改浏览器地址栏的访问路径,之前的路径已经不存在。

;