数据库
首页 > 数据库> > day32-Redis

day32-Redis

作者:互联网

学习目标

第一章-Redis介绍和安装

知识点-Nosql概述

1.目标

2.路径

3.讲解

3.1 什么是NOSQL

​ MySQL:关系型数据库 ①表与表之间存在关系 ②表与实体存在关系

​ NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库

​ 非关系型数据库只是关系型数据库的一个补充,并不是关系型数据库的替代品。

3.2.为什么需要学习NOSQL (三高)

​ 随着互联网的高速崛起,网站的用户群的增加,访问量的上升,传统(关系型)数据库上都开始出现了性能瓶颈,web程序不再仅仅专注在功能上,同时也在追求性能。所以NOSQL数据库应运而上,具体表现为对如下三高问题的解决:

3.3 主流的NOSQL产品

3.4NOSQL的特点

​ 在大数据存取上具备关系型数据库无法比拟的性能优势,例如:

4.小结

  1. NoSQL:非关系型数据库 是关系型数据库的一个补充。
  2. 为什么要使用NOSQL
    1. 高并发读写需求
    2. 高效率存储和访问的需求
    3. 高扩展性和高可用性需求
  3. 主流的NoSQL
    1. redis
    2. MongoDB

知识点-Redis概述

1.目标

2.路径

3.讲解

3.1.什么是Redis

​ Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,数据是保存在内存里面的. 官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s ,且Redis通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:

​ key是string类型,value可以是下面这五种类型

​ Redis支持的数据类型有五种:string、hash、list、set、zset

3.2 redis的应用场景

4.小结

  1. Redis:由C语言开发 高性能键值对存储的数据库,数据存储在内存中。
  2. Redis数据类型:string、hash、list、set、zset
  3. Redis的应用场景
    1. 缓存
    2. 任务队列
    3. 过期数据处理
    4. 分布式集群架构下的session共享
    5. 分布式锁实现
    6. ...

实操-window版Redis的安装

1.目标

2.路径

  1. Redis的下载

  2. Redis的安装

  3. 启动

3.讲解

3.1.windows版Redis的下载

​ 官方提倡使用Linux版的Redis,所以官网只提供了Linux版的Redis下载,我们可以从GitHub上下载window版的Redis,具体链接地址如下:

img

在今天的课程资料中提供的下载完毕的window版本的Redis:

img

3.2 Redis的安装

解压Redis压缩包后,见到如下目录机构:

目录或文件 作用
redis-benchmark 性能测试工具
redis-check-aof AOF文件修复工具
redis-check-dump RDB文件检查工具(快照持久化文件)
redis-cli 命令行客户端
redis-server redis服务器启动命令
redis.windows.conf redis核心配置文件

3.3 启动

先启动服务端,再启动客户端!

img

![](img

img)

4.小结

  1. redis目录结构
image-20210112170514886
  1. 启动
    1. 先启动服务端 redis-server.exe
    2. 再启动客户端 redis-cli.exe
  2. 注意:
    1. redis默认端口号6379
    2. redis默认连接不需要密码

实操-Redis的客户端安装

1.目标

​ 装Redis的客户端

2.步骤

image-20191223100124678

注意:

​ 1.使用客户端连接redis时,Redis服务端一定要开启

​ 2.我们一般不在Redis客户端下进行操作,主要就是通过Redis客户端方便查看我们存储哪些key

第二章-Redis的数据类型【重点】

知识点-redis中数据结构/类型

1.目标

2.路径

3.讲解

3.1Redis的数据类型【面试】

​ redis中存储的数据是以key-value的形式存在的.key是string类型,其中value支持5种数据类型 .在日常开发中主要使用比较多的有字符串string、哈希hash、字符串列表list、字符串集合set 四种类型,其中最为常用的是字符串类型

字符串(String)

​ 哈希(hash) 类似HashMap 适合存储对象(属性,属性值)

​ 字符串列表(list) 类似LinkedList

​ 字符串集合(set) 类似HashSet

​ 有序的字符串集合(sorted-set或者叫zset) 有序且唯一

3.2key

4.小结

  1. Redis数据类型
    1. string 字符串类型
    2. hash 类似java中的HashMap
    3. list 类似java中的LinkedList
    4. set 无序唯一 java中hashset
    5. zset 有序且唯一
  2. key的命名规则:项目:模块:key

知识点-Redis字符串(String)

1.目标

2.路径

  1. Redis字符串(String)概述
  2. 应用场景
  3. 常见命令
  4. 应用举例

2.讲解

2.1概述

​ string是redis最基本的类型,用的也是最多的,一个key对应一个value。 一个键最大能存储512MB.

2.2应用场景

  1. 缓存功能:字符串最经典的使用场景,redis作为缓存层,MySQL作为存储层,绝大部分请求数据都是在redis中操作,由于redis具有支撑高并发特性,所以缓存通常能起到加速读写和降低后端MySQL压力的作用。
  2. 计数器功能:比如视频播放次数,点赞次数。

2.3常见命令

命令 描述
SET key value 设置指定 key 的值
GET key 获取指定 key 的值
DEL key 删除key
GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。
SETNX key value 只有在 key 不存在时设置 key 的值。
INCR key 将 key 中储存的数字值增一。
INCRBY key increment 将 key 所储存的值加上给定的增量值(increment) 。
DECR key 将 key 中储存的数字值减一。
DECRBY key decrement key 所储存的值减去给定的减量值(decrement) 。

2.4应用举例

商品编号、订单号采用string的递增数字特性生成。

定义商品编号key:items:id
192.168.101.3:7003> INCR items:id
(integer) 2
192.168.101.3:7003> INCR items:id
(integer) 3

4.小结

4.1string

  1. string类型:是Redis中使用最多的数据类型,经常使用在缓存处理,计数,数据过期处理这些场景中。
  2. set key value
  3. get key
  4. del key
  5. setex key seconds value
  6. setnx key value
  7. incr key

4.2使用string的问题

​ 假设有User对象以JSON序列化的形式存储到Redis中,User对象有id,username、password、age、nickname等属性,存储的过程如下:
​ 保存: User对象 ==> json(string) ==>redis

​ 更新:redis == >json(string) ==> user对象 ==>修改age ==> json == >再存进去

​ 如果业务只想更新用户年龄age,这个时候按正常,就需要取出json字符串,转为user对象,重新设置age属性值,然后再将User对象==> json(string) ==>redis ,优化?hash存储 就可以直接修改age即可 不需要转来转去

但是:实际开发中,基本不会在redis中修改数据,redis主要负责存储数据作缓存处理,等待获取。如果数据发生改变,则会直接删除redis中存储的原有数据,等待下一次查询之后再加入到redis中。

知识点-Redis 哈希(Hash)

1.目标

2.路径

  1. Redis 哈希(Hash)概述
  2. 应用场景
  3. 常见命令
  4. 应用举例

3.讲解

3.1 概述

​ Redis中hash 是一个键值对集合。 类似于java中的hashmap

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

​ Redis存储hash可以看成是String key 和String value的map容器. 也就是说把值看成map集合.

hash特别适合存储对象相比较而言,将一个对象类型存储在Hash类型里要比存储在String类型里占用更少的内存空间并方便存取整个对象

image-20191223104457481

3.2应用场景

​ 用一个对象来存储用户信息,商品信息,订单信息等等。 存储对象

3.3常见命令

命令 命令描述
hset key filed value 将哈希表 key 中的字段 field 的值设为 value
hmset key field1 value1 [field2 value2]... 同时将多个 field-value (字段-值)对设置到哈希表 key 中
hget key filed 获取存储在哈希表中指定字段的值
hmget key filed1 filed2 获取多个给定字段的值
hdel key filed1 [filed2] 删除一个或多个哈希表字段
hlen key 获取哈希表中字段的数量
del key 删除整个hash(对象)
HGETALL key 获取在哈希表中指定 key 的所有字段和值
HKEYS key 获取所有哈希表中的字段
HVALS key 获取哈希表中所有值

3.4应用举例 存对象

存储商品信息

HMSET items:1001 id 3 name apple price 999.9 

4.小结

​ 1. hash类型适合存储对象,类似于java中hashMap 是一个键值对的存储 key可以存对象属性,value可以存属性值

知识点-Redis 列表(List)

1.目标

2.路径

  1. List类型
  2. Redis 列表(List)概述
  3. 应用场景
  4. 常见命令
  5. 应用举例

3.讲解

3.1List类型

ArrayList使用数组方式存储数据,所以根据索引查询数据速度快,而新增或者删除元素时需要设计到位移操作,所以比较慢。

​ LinkedList使用双向链表方式存储数据,每个元素都记录前后元素的指针,所以插入、删除数据时只是更改前后元素的指针指向即可,速度非常快。然后通过下标查询元素时需要从头开始索引,所以比较慢,但是如果查询前几个元素或后几个元素速度比较快。

img

img

3.2概述

​ 列表类型(list)可以存储一个有序的字符串列表(链表),常用的操作是向列表两端添加元素,或者获得列表的某一个片段。
​ 列表类型内部是使用双向链表(double linked list)实现的,所以向列表两端添加元素的时间复杂度为O(1),获取越接近两端的元素速度就越快。这意味着即使是一个有几千万个元素的列表,获取头部或尾部的10条记录也是极快的。

衡量一个程序的好坏:时间复杂度、空间复杂度

衡量一个程序是否合格高效,主要有两个维度:运行时间(程序的效率)、运行空间

时间复杂度:衡量程序运行是否高效

空间复杂度:衡量程序运行占用空间大小

eg:现在老师布置了一个作业,要求张三和李四去设计程序完成,张三写的程序运行时间50ms,占用空间5000M,李四写的程序运行时间5s,占用空间500M。

java程序:空间换时间,宁肯牺牲空间(+内存 +主机),也要保证时间

https://blog.csdn.net/qq_41523096/article/details/82142747

3.2应用场景

​ 如好友列表,粉丝列表,消息队列,最新消息排行等。

lpush/rpush方法就相当于将消息放入到队列中,lpop/rpop就相当于从队列中拿出消息进行消费

​ list列表底层采用双向链表实现,但是功能上又接近于队列。

3.3.常见命令

命令 命令描述
lpush key value1 value2... 将一个或多个值插入到列表头部(左边)
rpush key value1 value2... 在列表中添加一个或多个值(右边)
lpop key 左边弹出一个 相当于移除第一个
rpop key 右边弹出一个 相当于移除最后一个
llen key 返回指定key所对应的list中元素个数
LINDEX key index 通过索引获取列表中的元素
LINSERT key BEFORE| AFTER pivot value 在列表元素前或后插入元素 eg:linsert words before c e
pivot表示列表中的元素 value表示新插入的值

3.4应用举例

商品评论列表

4.小结

  1. List是一个字符串链表,可以当作队列使用,通过lpush、rpush向队列中添加数据,通过lpop、rpop从队列中获取数据消费

知识点-Redis 集合(Set)

1.目标

2.路径

  1. Redis 集合(Set)概述
  2. 应用场景
  3. 常见命令
  4. 应用举例

3.讲解

3.1概述

​ Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

​ Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的时间复杂度都是O(1)。集合中最大的成员数为 2的32次方 -1 (4294967295, 每个集合可存储40多亿个成员)。

​ Redis还提供了多个集合之间的交集、并集、差集的运算

​ 特点:无序+唯一

3.2应用场景

​ 投票记录

​ 共同好友、共同兴趣、好友推荐【A有这些好友 而你没有】

3.3.常见命令

命令 命令描述
sadd key member1 [member2] 向集合添加一个或多个成员
srem key member1 [member2] 移除一个成员或者多个成员
smembers key 返回集合中的所有成员,查看所有
SCARD key 获取集合的成员数
SPOP key 返回集合中移除的一个随机元素
SDIFF key1 [key2] 返回给定所有集合的差集
SUNION key1 [key2] 返回所有给定集合的并集
SINTER key1 [key2] 返回给定所有集合的交集

3.4应用举例

共同好友

4.小结

  1. Redis中的set是无序唯一,类似java中的hashset
  2. 使用场景:
    1. 投票 唯一
    2. 抽奖 spop
    3. 共同好友 sinter
    4. 好友推荐 sdiff

知识点-Redis 有序集合(sorted set | zset)

1.目标

2.路径

  1. sorted set介绍
  2. sorted set 应用场景
  3. sorted set 命令
  4. sorted set 具体示例

3.讲解

3.1概述

Redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序

有序集合的成员是唯一的,但分数(score)却可以重复

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

特点: 有序(根据分数排序)+唯一

3.2应用场景

排行榜:例如音乐排行榜 今年最流行十首华语歌曲 视频排行榜 元素:视频名称 score: 点击量

3.3.常见命令

命令 命令描述
ZADD key score member [score member ...] 增加元素
ZSCORE key member 获取元素的分数
ZREM key member [member ...] 删除元素
ZCARD key 获得集合中元素的数量
ZRANGE key start stop[WITHSCORES] 获得排名在某个范围的元素列表
查看所有元素:zrange key 0 -1
倒序排列查看:zrevrange key 0 2

3.4应用举例

商品销售排行榜

--商品编号1001的销量是9,商品编号1002的销量是10 ,商品编号1003的销量是15
127.0.0.1:6379> zadd items:sellsort 9 1001 10 1002 15 1003
--商品编号1001的销量加1
127.0.0.1:6379> zincrby items:sellsort 1 1001
--商品销量前10名
127.0.0.1:6379> zrevrange items:sellsort 0 9

4.小结

  1. ZSET:有序集合(有序+唯一) 有序的实现是为每个元素添加一个double类型的分数,实现排序
  2. 使用场合:排行榜

第三章-Redis通用的操作,发布订阅和持久化【了解】

知识点-Redis通用的操作

1.目标

2.路径

3.讲解

3.1 通用操作

3.2多数据库性

​ redis默认是16个数据库, 编号是从0~15. 【默认是0号库】

4.小结

  1. exists key 判断是否有这个key
  2. expire key 秒数 设置这个key在缓存中的存活时间
  3. ttl key 展示指定key的剩余时间(-1:永不过期 -2:已过期或不存在)
  4. select index 切换库

知识点-订阅发布机制 【了解】

1.目标

2.路径

  1. 什么是Redis订阅发布机制
  2. 相关的命令
  3. 订阅发布实操

3.讲解

3.1什么是Redis订阅发布机制

​ Redis 发布订阅(pub/sub)是进程间一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。(用户收听广播)

​ Redis 客户端可以订阅任意数量的频道。

3.2相关的命令

序号 命令及描述
1 PUBLISH channel message 将信息发送到指定的频道。
2 SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。
3 UNSUBSCRIBE [channel [channel ...]] 指退订给定的频道

3.3订阅发布实操

SUBSCRIBE nba
PUBLISH  nba aaa

4.小结

  1. Redis 发布订阅(pub/sub)是进程间一种消息通信模式, 工作里面一般使用MQ【消息中间件 rabbitMQ kafaka RocketMQ】

知识点-Redis的持久化【面试】

1.目标

​ Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘(文件)中,这一过程就是持久化

​ Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。

2.路径

3.讲解

3.1RDB持久化机制

3.1.1概述

​ RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。 这种方式是默认已经开启了,不需要配置.

3.1.2 RDB持久化机制的配置

image-20210716121149516

其中,上面配置的是RDB方式数据持久化时机:

关键字 时间(秒) key修改数量 解释
save 900 1 每900秒(15分钟)至少有1个key发生变化,则dump内存快照
save 300 10 每300秒(5分钟)至少有10个key发生变化,则dump内存快照
save 60 10000 每60秒(1分钟)至少有10000个key发生变化,则dump内存快照

3.2 AOF持久化机制

3.2.1概述

​ AOF持久化机制会将每一个收到的写命令都通过write函数追加到文件中,默认的文件名是appendonly.aof。 这种方式默认是没有开启的,要使用时候需要配置.【一旦手动开启AOF持久化之后,将不再使用RDB持久化了】

3.2.2AOF持久化机制配置
3.2.2.1开启配置

image-20210716122116958

img

img

3.2.2.2配置详解

image-20210806120854418

关键字 持久化时机 解释
appendfsync always 每执行一次更新命令,持久化一次
appendfsync everysec 每秒钟持久化一次
appendfsync no 不持久化

4,小结

Redis持久化:表示将redis在内存中存储的数据 同步保存到硬盘上,进行一个永久保存。

Redis持久化有两种方式:RDB【默认 二进制文件 有一定的时间间隔】、AOF【需要打开 命令文件 默认每秒】

一台Redis服务器主机RDB和AOF只能使用一种,如果设置了AOF持久化方式,就关闭了RDB方式持久化。

4.1RDB

优点
缺点

4.2AOF

优点
缺点

4.3选择

第四章-Jedis 【重点】

案例-Jedis的快速入门

1.目标

2.路径

  1. jedis的介绍

  2. Jedis的入门

3.讲解

3.1 jedis的介绍

​ Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。 在官方网站里列一些Java的客户端,有JedisRedissonlettuce、JDBC-Redis、等其中官方推荐使用Jedis和Redisson。 在企业中用的最多的就是Jedis,Jedis同样也是托管在github上.

说白了Jedis就是使用Java操作Redis的客户端(工具包) jedis=JDBC+驱动

地址:https://github.com/xetorthio/jedis。

文档地址:http://xetorthio.github.io/jedis/

方法 解释
new Jedis(host, port) 创建jedis对象,参数host是redis服务器地址,参数port是redis服务端口
set(key,value) 设置字符串类型的数据
get(key) 获得字符串类型的数据
hset(key,field,value) 设置哈希类型的数据
hget(key,field) 获得哈希类型的数据
lpush(key,values) 设置列表类型的数据
lpop(key) 列表左面弹栈
rpop(key) 列表右面弹栈
sadd(String key, String... members) 设置set类型的数据
zrange(String key, long start, long end) 获得在某个范围的元素列表
del(key) 删除key
exists(key) 判断key是否存在

3.2 Jedis的入门

需求: 使用java代码操作Redis 进行增(改)删查

步骤:

  1. 创建项目,添加jedis jar包
  2. 创建jedis对象
  3. 调用方法操作redis
  4. 关闭jedis对象 释放资源
package com.itheima.test;

import redis.clients.jedis.Jedis;

import java.util.Set;

public class Demo01 {
    public static void main(String[] args) {

        //1.创建jedis对象
        Jedis jedis = new Jedis("localhost",6379);
        //2.调用方法
        //2.1:string类型操作
        //获取value
        String akey = jedis.get("akey");
        System.out.println("akey = " + akey);
        //判断key是否存在
        Boolean flag = jedis.exists("akey");
        System.out.println("akey是否存在:"+flag);
        //jedis.del("akey");  删除key
        //存储key-value
        jedis.set("dkey","ddd");

        //2.2:hash类型
        jedis.hset("user1","name","zs");
        String name = jedis.hget("user1", "name");
        System.out.println("name = " + name);

        //2.3:list类型
        jedis.rpush("list1","a","b","c");
        System.out.println(jedis.lindex("list1", 2));

        //2.4:set类型
        jedis.sadd("set1","a","b","c");
        Set<String> set1 = jedis.smembers("set1");
        for (String s : set1) {
            System.out.println(s);
        }

        //3.关闭对象
        jedis.close();
    }
}

4.小结

  1. Jedis: java操作Redis的客户端, 工具包(等价于 JDBC+数据库驱动),操作redis,也就是把之前redis的命令封装成了方法。
  2. 使用步骤
    • 导入jar包
    • 创建jedis对象
    • 调用方法
    • 关闭对象

知识点-Jedis进阶

1.目标

2.路径

  1. jedis连接池介绍
  2. jedis连接池的使用
  3. 工具类的抽取

3.讲解

连接池:存放连接对象的容器 避免连接对象的频繁创建销毁,造成资源浪费,提高系统性能

3.1 jedis连接池的基本概念

​ jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的池化技术,jedisPool在创建时初始化一些连接资源存储到连接池中,使用jedis连接资源时不需要创建,而是从连接池中获取一个资源进行redis的操作,使用完毕后,不需要销毁该jedis连接资源,而是将该资源归还给连接池,供其他请求使用。

3.2jedis连接池的使用

需求: 从Jedis的连接池里面获得jedis对象使用

步骤:

  1. 创建JedisPoolConfig对象
  2. 创建JedisPool对象
  3. 获取Jedis对象
  4. 调用方法
  5. 归还连接对象
public class Demo02 {
    public static void main(String[] args) {
        //1. 创建JedisPoolConfig对象
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(5);
        config.setMaxWaitMillis(5000);
        //2. 创建JedisPool对象
        JedisPool jedisPool = new JedisPool(config, "localhost", 6379);
        //3. 获取jedis对象
        Jedis jedis = jedisPool.getResource();
        //4. 调用方法  需求:如果akey存在 获取akey的值  ; 如果akey不存在 创建一个akey=aaa存入redis中
        if(jedis.exists("akey")){
            System.out.println(jedis.get("akey"));
        }else{
            jedis.set("akey","aaa");
        }
        //5. 归还jedis对象到Jedis连接池
        jedis.close();
    }
}

3.3Jedis工具类的抽取

目的: 1.保证池子只有一个 2.获得jedis对象 3.归还

步骤:

  1. 创建JedisUtils工具类
  2. 获取jedis对象
  3. 归还jedis对象
  4. 保证池子只有一个 使用静态代码块创建连接池对象
package com.itheima.utils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Jedis工具类
 *  1.提供获取jedis对象的方法  getJedis();
 *  2.提供归还jedis对象的方法  close(Jedis jedis);
 *  优化:让jedisPool对象只有一个  采用单例模式  声明一个静态变量JedisPool对象  然后使用静态代码块初始化JedisPool对象
 */
public class JedisUtils {

    private static JedisPool jedisPool;

    static{
        //1. 创建JedisPoolConfig对象
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(5);
        config.setMaxWaitMillis(3000);
        //2. 创建JedisPool对象
        jedisPool = new JedisPool(config,"127.0.0.1",6379);
    }

    /**
     * 获取jedis对象
     * @return
     */
    public static Jedis getJedis(){
        //3. 获取jedis对象
        return jedisPool.getResource();
    }

    /**
     * 归还jedis对象
     * @param jedis
     */
    public static void close(Jedis jedis){
        if(jedis!=null){
            jedis.close();
        }
    }
}

3.4.3 作业

把JedisUtils里面配置信息(eg:host和port) 抽取到 jedis.properties里面

4.小结

  1. 使用JedisPool目的: 为了jedis对象复用,使用了池化技术。

案例-使用Redis优化省份的展示

1.需求

​ 访问index.html页面,使用ajax请求加载省份列表 前端(vue 发送ajax请求) 后台(Servlet 响应json)

1571210295308

2.分析

2.1直接从MySQL获得

  1. 创建数据库;创建项目,创建包结构,javabean;jar包、工具类、配置文件;页面

  2. 前端|html 在index.html中发送ajax请求 在生命周期函数created时发送

    data:{
        provinces:[]
    },
    created:function(){
        axios.get("请求地址").then(response=>{
            if(response.data.flag){
               this.provinces = response.data.result;
               }else{
                   alert(response.data.message);
               }
        });
    }
    
    //使用v-for遍历省份列表数据 显示到下拉列表中
    
  3. 后台|Servlet

    //1.获取请求参数  没有
    
    /* 判断redis中是否存储的有省份列表数据 有 就从redis中获取响应  没有 从MySQL中查询 存入redis一份*/
    //redis中省份列表数据的key为 province_list
    if(jedis.exists("province_list")){
        //从redis中获取响应
    }else{
        //从MySQL中查询 存入redis一份
        //2.调用业务处理  【Service返回省份列表集合数据  List<Province>】
    	//3.响应json数据
    	//3.1:封装list到result对象
    	//3.2:将result对象以json格式响应给客户端浏览器
    }
    
    

3.代码实现

3.1准备工作

create database day32;
use day32;

CREATE TABLE `province` (
  `pid` int NOT NULL AUTO_INCREMENT,
  `pname` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

INSERT INTO `province` VALUES ('1', '广东');
INSERT INTO `province` VALUES ('2', '湖北');
INSERT INTO `province` VALUES ('3', '湖南');
INSERT INTO `province` VALUES ('4', '四川');
INSERT INTO `province` VALUES ('5', '山东');
INSERT INTO `province` VALUES ('6', '山西');
INSERT INTO `province` VALUES ('7', '广西');
package com.itheima.bean;

import java.io.Serializable;

public class Province implements Serializable {
	
	private Integer pid;
	private String pname;
	public Integer getPid() {
		return pid;
	}
	public void setPid(Integer pid) {
		this.pid = pid;
	}
	public String getPname() {
		return pname;
	}
	public void setPname(String pname) {
		this.pname = pname;
	}
	@Override
	public String toString() {
		return "Province [pid=" + pid + ", pname=" + pname + "]";
	}
}

3.2代码实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/vuejs-2.5.16.js"></script>
    <script src="js/axios-0.18.0.js"></script>
</head>
<body>
    <div id="app">
        省: <select id="pSelect">
                  <option>请选择</option>
                  <option v-for="(province,index) in provinces">{{province.pname}}</option>
           </select>
    </div>

    <script>
    	var vm = new Vue({
    		//指定vue使用的区域  不可以指定为body
    		el:"#app",
    		//声明数据  1.可以封装请求参数  2.接收响应数据
    		data:{
                provinces:[]
    		},
    		//声明函数
    		methods: {

    		},
            created:function () {
                //1.获取请求参数 【没有】
                //2.发送ajax请求
                axios.get("ProvinceServlet").then(response=>{
                    //3.根据响应数据 进行处理
                    if(response.data.flag){
                        //请求处理成功 数据绑定
                        //response:响应信息  response.data=result对象   response.data.result=result对象中的result属性 用于封装查询返回的数据
                        this.provinces = response.data.result;
                    }else{
                        //请求处理失败  弹窗提示
                        alert(response.data.message);
                    }
                });
            }
    	});
    </script>
</body>
</html>
package com.itheima.web;

import com.alibaba.fastjson.JSON;
import com.itheima.bean.Province;
import com.itheima.bean.Result;
import com.itheima.service.ProvinceService;
import com.itheima.utils.JedisUtils;
import com.itheima.utils.JsonUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@WebServlet("/ProvinceServlet")
public class ProvinceServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            //1.获取请求参数  【没有】
            /*判断Redis中是否存储province_list这个键  存在表示redis中有省份列表数据  不存在表示没有 需要去MySQL数据库中查询*/
            //2.1:获取jedis对象
            Jedis jedis = JedisUtils.getJedis();
            //2.2:判断province_list键是否存在
            if(jedis.exists("province_list")){
                //true 存在 从redis中获取省份列表数据响应
                System.out.println("从redis中获取");

                //注意:此时返回的是json数据字符串形式  在进行响应给前台时 需要将其转为list集合再封装
                //如果将一个字符串再转为json数据  就会变成普通字符串 就不再是json数据格式了,会导致前端无法正常解析
                //Result result = new Result(true, "查询成功!",province_list);

                String province_list = jedis.get("province_list");
                Result result = new Result(true, "查询成功!",JSON.parse(province_list));
                JsonUtils.printResult(response,result);
            }else{
                //false 不存在  从MySQL中获取省份列表数据响应
                System.out.println("从MySQL中获取");
                //2.调用业务处理 返回省份列表List<Province>
                ProvinceService provinceService = new ProvinceService();
                List<Province> list = provinceService.getList();

                /*第一次查询 redis中时没有省份列表数据的  需要从MySQL数据库中查询出来后存入redis一份*/
                jedis.set("province_list", JSON.toJSONString(list));

                //3.封装响应数据到result对象以json格式响应给前台
                Result result = new Result(true, "查询成功!", list);
                JsonUtils.printResult(response,result);
            }

        } catch (Exception e) {
            e.printStackTrace();
            Result result = new Result(false, "服务器异常!");
            JsonUtils.printResult(response,result);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
package com.itheima.service;

import com.itheima.bean.Province;
import com.itheima.dao.ProvinceDao;

import java.sql.SQLException;
import java.util.List;

public class ProvinceService {

    /**
     * 查询所有省份列表信息
     * @return
     */
    public List<Province> findList() throws SQLException {
        //调用dao
        ProvinceDao provinceDao = new ProvinceDao();
        return provinceDao.findList();
    }
}
package com.itheima.dao;

import com.itheima.bean.Province;
import com.itheima.utils.C3P0Utils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;

public class ProvinceDao {

    //查询所有省份列表信息
    public List<Province> findList() throws SQLException {
        //操作数据库
        QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
        String sql = "select * from province";
        return queryRunner.query(sql,new BeanListHandler<>(Province.class));
    }
}

4.小结

  1. 优化

    • 先判断redis中是否存储省份列表数据 jedis.exists("province_list");

    • 存在:直接从redis中获取 注意:redis中存的String类型 所以取出后需要转换一下

      //注意2:存入redis的是json字符串 存进去之后又变成了普通String  需要转回来,不转的话前端无法正常解析
      Result result = new Result(true,"从redis中查询成功!", JSON.parse(province_list));
      
    • 不存在:从MySQL中查询,查询之后存入redis,然后响应

      //注意1:在将数据存入redis中时  需要转成json字符串存入
      jedis.set("province_list",JSON.toJSONString(list));
      

案例-使用Redis完成邮箱验证码的校验

1.需求

1571727394934

2.分析

image-20210621161914657

2.1发送邮件思路

  1. 填写邮箱地址,发送激活链接(附加邮箱地址和激活码)
  2. 将生成的激活码存入redis,24h
  3. 发送激活邮件到用户邮箱

2.2验证思路

  1. 创建一个激活Servlet activeServlet
  2. 获取redis中的验证码与激活链接的验证码进行比对
  3. 激活成功(更新账号状态status为1,表示启用 删除redis中存储的该验证码)

3.代码实现

3.1发送邮件代码

  /******************************注册时发送激活邮件***************************************/
//2.1:生成激活码   UUID 
String code = UUIDUtils.generateUUID();
// 2.2:将激活码存redis中 key-value   ("邮箱地址","激活码")
// 2.3:设置过期时间24h
Jedis jedis = JedisUtils.getJedis();
jedis.setex(user.getEmail(),60*60*24,code);
// 2.4:发送激活链接到用户邮箱   active?email=?&code=?
MailUtil.sendMail(user.getEmail(),"账户激活","尊敬的用户,您好,请点击<a href='http://localhost:8080"+request.getContextPath()+"/active?email="+user.getEmail()+"&code="+code+"'>该链接</a>进行账户激活使用。");
/******************************注册时发送激活邮件***************************************/

3.2验证代码

package com.itheima.web;

import com.itheima.utils.JedisUtils;
import redis.clients.jedis.Jedis;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(value = "/active")
public class ActiveServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取请求参数
        String email = request.getParameter("email");
        String activeCode = request.getParameter("activeCode");
        //1.1:获取redis中存储的用户激活信息  key:用户邮箱 value:激活码
        Jedis jedis = JedisUtils.getJedis();
        Boolean flag = jedis.exists(email);
        if(flag){
            String code = jedis.get(email);
            if(code.equals(activeCode)){
                //激活成功  1.修改用户status=1       2.删除redis中存储的验证码
                response.getWriter().print("active success");
            }else{
                //激活失败
                response.getWriter().print("active fail");
            }
        }else{
            //激活失败
            response.getWriter().print("active fail");
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

4.小结

总结

  1. 概念

    1. NoSQL:泛指非关系型数据库
    2. Redis:是一个由C语言开发的高性能键值对数据库,数据存储在内存中。
    3. Redis的安装和使用
      1. 先启动服务端 redis-server.exe
      2. 再启动客户端 redis-cli.exe
  2. Redis的数据类型

    1. key为string类型,value有五种类型:string、hash、list、set、zset
    2. string
      1. set key value
      2. get key
      3. del key
      4. exists key
      5. setex key seconds value
      6. setnx key value
      7. incr key
  3. Redis通用操作

    1. expire key
    2. ttl key
      1. 正数:表示key的剩余时间
      2. -1:永不过期
      3. -2:不存在或已删除
    3. select index:切换库
  4. Redis持久化

    1. RDB
    2. AOF
  5. Jedis

    1. 使用jedis在java中操作redis
      1. 导入jar包
      2. 创建jedis对象
      3. 调用方法
      4. 关闭对象
    2. 使用jedis连接池
      1. 创建JedisPoolConfig对象
      2. 创建JedisPool对象
      3. 获取jedis对象
      4. 调用方法
      5. 归还jedis对象
    3. 抽取jedis工具类
  6. 练习

    1. Redis的数据类型练习【重点是String】

    2. 使用Jedis操作Redis

    3. 案例一

    4. 理解持久化【先记忆一下 RDB和AOF的区别】

    5. 案例二

标签:redis,day32,value,jedis,key,import,Redis
来源: https://www.cnblogs.com/ofanimon/p/16188227.html