shoppe项目01----Redis

Redis介绍

  1. Redis 是开源的,免费的,高性能的 非关系形数据库。
  2. 数据存储在内存,以key-value形式存储,类似于我们学习的字典 {name: ‘jack’ }
  3. 可以设置过期时间,过期自动删除,也可以做持久化。

关系型数据库: MySQL
MySQL的缺陷:
1. 读取的时候相对较快, 但是写入数据是比较慢的, 读取速度是1w/s. 写入速度: 1000/s。
2. 读写时容易混淆,会读取出脏数据,需要对Mysql读写做限制.
3. 需要定义严格的表结构,插入数据需要满足完整性约束。
4. 数据存储在磁盘,相对于内存数据库,读写速度慢。

非关系型数据库: Redis 在非关系型数据库中没有表这个概念,也就没有表关系这样的概念,都是k/v 格式的。

Redis 优势:

  • 性能极高 – Redis读的速度是11w次/s,写的速度是8.1w次/s ,都是基于内存的,读写速度比较快。
  • 丰富的数据类型 – Redis支持 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子性 – Redis的所有操作都是原子性的,要么成功执行,要么失败不执行。支持简单的事务,即原子性,通过MULTI和EXEC指令包起来。如下所有的操作全部执行或者全部不执行
>multi
>set name jack
>set age 23
>set sex male
>exec
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

Redis的缺点:

  • 基于内存型数据库, 主机断电时数据全部丢失。
  • key同时过期会造成Redis数据库的“雪崩”,容易把整个服务搞垮。

Redis安装

这里以windows系统为例:
Redis 支持 32 位和 64 位。这个需要根据操作系统的实际情况选择,这里我们下载64bit。

Redis-x64-5.0.10.msi安装到 自己的windows。

注意:把 redis 的路径加到系统的环境变量

然后就可以使用客户端连接

redis-cli -h localhost -p 6379

Redis配置

找到安装目录下的配置文件redis.windows-service.conf,修改配置文件实现如下需求。
在这里插入图片描述

  1. 配置密码
    搜索requirepass
    设置密码
    重启redis服务(任务管理器)
    使用密码连接
redis-cli -h localhost -p 6379
>auth ****
>ping  
  1. 配置远程登录
    注释 bind 127.0.0.1
    取消保护模式 protected-mode no
    重启redis服务(在任务管理器中操作),如下:
    在这里插入图片描述
    模拟远程连接
    在这里插入图片描述
    完成!

Redis通用命令

redis默认有16个 数据库(0-15)
select 3 切换到数据库3

info 查看redis服务的信息
info replication查看主从复制的状况

keys * 查看所有的key, 生产环境中不使用
可能阻塞redis

查看key的数据类型
type key1

key 是否存在
exists key1

删除一个key
del key1

重命名
rename key key1

清空数据库
flushdb/flushall

String类型

k e y − − > 字符串 / 数值 key-->字符串/数值 key>字符串/数值

  1. key 不宜过长,占用内存,也不宜过短,可读性差
    如:user:lauf
  2. 值,为字符串或者数值,最多存储512M

数据操作

  1. 设置key-value
>set name jack
>mset name jack age 23 addr China
>append key val  追加

python实现

import redis
r=redis.Redis(host="localhost",port=6379,db=0)
r.set("name","jack")
r.mset({"name":"jack","age":23,"hobby":"football"})
  1. 获取key的值
get name
mget name age hobby

python实现

r.get("name")  #返回字节串
r.mget("name","age","hobby") #返回值列表
  1. 设置key时,设置过期时间
#10s后过期
set name jack ex 10
#不存在时,设置key
set name jack nx

python实现

r.set("name","jack",ex=10)
r.set("name","666",nx=True)
  1. 获取字符串值的长度
strlen name

python实现

r.strlen("name")--->int
  1. 获取字符串的分片
set name jack
getrange name 0 1 #包含1
-->ja

python实现

r.set("name","jack")
r.getrange("name",0,1) 
-->分片的字节串b'ja'
  1. 设置字符串的片段值
set name beikehan
setrange name 1 oo
-->bookehan

python实现

r.setrange("name",1,"oo")
  1. 数值加1、减1
set age 23
incr age  只能整型数值
-->24
decr age
-->23
  1. 数值加5、减5
set age 10
incrby age 5    只能整形
-->15
decrby age 5
-->10

incrbyfloat age 1.3   转为字符串
incrbyfloat age -1.2

字符串的使用场景

  1. 作为缓存
  2. 并发计数,点赞、秒杀
  3. 带有效期的验证码,过期自动删除

练习:基于django实现验证码的生成与存储

  • 创建一个django项目,命名test_sms_code
  • 为项目创建一个虚拟环境myenv,保证不会污染自己的默认环境
  • 配置项目的模板templates、静态文件static等
  • 配置路由,编写视图
  • get /v1/login/ 返回如下页面:
    在这里插入图片描述

点击生成验证码, 后端生成随机码,存储到redis,过期时间2分钟,返回前端;
前端输入验证码,失去焦点,触发验证。

设置过期时间

#1 10s过期
set name jack ex 10
#2 
set name jack
expire name 10 -->10s
pexpire name 10 -->10ms

#查看多久过期
ttl name
-->返回-2 key不存在
-->返回-1 key存在,但没有过期时间
-->返回具体时间,剩余过期时间

#设置永不过期
persist name

位图操作

  1. redis可以操作字符串类型的二进制位
set name a
#"a"对应的比特位
-->0110 0001
#获取比特位
getbit name 1  #这里的1为偏移量,若超出,则补最小字节的bit位(0)
-->1
setbit name 1 0
-->0010 0001
get name 
-->"!"
  1. 统计bit中1 的个数
set name a
#统计字符串所有bit位中1的个数
bitcount name
-->3
#统计字符串bit位中第一字节的1的个数
bitcount name 0 0
  1. 使用场景
    使用bit位记录用户的登录状态,统计一年中登录的天数,
    可以有效节约内存
#设置第1天的登录
setbit user:1 0 1
#第2天
setbit user:1 1 0
#第3天
setbit user:1 2 1
...
#统计总共登录了多少天
bitcount user:1

String类型的练习

  1. 存储生成的短信验证码,方便下次验证,注意:短信验证码的有效期为10分钟

    127.0.0.1:6379> set sms_code:1731111111 637905 EX 300  # 存储 1731111111该手机号的短信验证码 637905, 过期时间是5分钟
    
  2. 存储标志,防止短信验证码发送过于频繁,1分内只能发送一次

    127.0.0.1:6379> set sms_code_flag:1731111111  1  EX 60  # 存储 1731111111该手机号是否发送短信验证码的标志, 过期时间是60s
    
  3. 取出短信验证码

    127.0.0.1:6379> get sms_code:1731111111 # 取出短信验证码,过期之后,取出为(nil)
    "637905"
    

List

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

类似: {name:[1,2,3,4,5,6,]}

插入列表

# 头插法
lpush key val1 val2 ...
127.0.0.1:6379> lpush numbers 1 2 3
(integer) 3

# 尾插法
127.0.0.1:6379> rpush numbers 8 9 0
(integer) 6

更新列表

# 修改某下标的值
lset key index val
127.0.0.1:6379> lset numbers 5 10  # 注意: redis中下标也是从0开始
OK

删除列表

# 头删法
lpop key # 删除第一个值, 并立即返回该值
127.0.0.1:6379> lpop numbers
"3"

# 尾删法
rpop key # 删除最后一个值, 并立即返回
127.0.0.1:6379> rpop numbers
"10"

#列表为空时,阻塞的删除
blpop  mylist  10
brpop mylist 10

# 删除指定的值
lrem key count value # 返回的是删除的个数
127.0.0.1:6379>lrem numbers 0 2  # 删除所有值为2的元素
(integer) 4

127.0.0.1:6379>lrem numbers -2 1  # 从表尾开始删除2个值为1的元素
(integer) 2
 
127.0.0.1:6379> lrem numbers 2 1  # 从表头开始删除2个值为1的元素
(integer) 2

# 截取数据
ltrim key start stop
127.0.0.1:6379> ltrim numbers 2 5  # 保留下标为 【2,5】之间的所有元素,删除其余元素
OK

查询列表

lrange key start stop # 返回指定区间内的内容
127.0.0.1:6379> lrange numbers 0 -1
1) "3"
2) "2"
3) "1"

llen key  #获取列表的长度

List类型练习

  1. 将id为1的商品存入用户173的历史记录中

    127.0.0.1:6379> lrem history:173 0 1  # 先移除 用户173历史记录中 所有id为1的商品记录
    (integer) 0
    
    127.0.0.1:6379> lpush history:173 1 # 将 id为1的商品存入 用户173的历史记录中
    (integer) 1
    
    127.0.0.1:6379> ltrim history:173 0 4  # 保留 历史记录中的前5条商品数据
    OK
    
  2. 查询用户173的历史记录

    127.0.0.1:6379> lrange history:173 0 -1  # 查询列表中的所有元素
    1) "1"
    

Hash

Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储字典数据。

插入哈希

# 设置单个 hset key field value 
127.0.0.1:6379> hset user:123 name jack 
(integer) 1
# 设置多个 hmset key field value [field2 value2]  # 同时将多个 field-value (域-值)对设置到哈希表中;
#键和字段存在时,属于更新
127.0.0.1:6379> hmset user:123 name xiaomi age 23 gender man # 存储用户123的个人信息{'name': 'xiaomi', 'age': 23, 'gender': '男'}
(integer) 3

hincrby key field increment  # 为哈希表 key 中的指定字段的整数值加上增量
127.0.0.1:6379> hincrby user:123 age 5  # 用户123的年龄加5岁
(integer) 24

查询哈希

hget key field #指定字段的值
127.0.0.1:6379> hget user:123 name
"xiaomi"

hgetall key # 获取所有字段和值
127.0.0.1:6379> hgetall user:123
1) "name"
2) "xiaomi"
3) "age"
4) "24"
5) "gender"
6) "man"

hkeys key  #获取所有的字段
hvals key   #获取所有的值

删除哈希

hdel key field1 [field2] # 删除一个或多个哈希字段, 返回删除的个数
127.0.0.1:6379> hdel user:123 gender # 用户123的性别
(integer) 1 

Hash类型练习

  1. 更新用户123 的购物车中id为3的商品数量

    127.0.0.1:6379> hincrby cart_123 3 5  # 有则新增,无则插入
    (integer) 5
    127.0.0.1:6379> hincrby cart_123 3 -2  # 有则新增,无则插入
    (integer) 3
    
  2. 修改用户123的购物车中id为3的商品数量为5个

    127.0.0.1:6379> hset cart_123 3 5  # 更新
    (integer) 1
    
  3. 获取用户123的所有购物车数据

    127.0.0.1:6379> hgetall cart_123
    1) "3"  # 商品id为3
    2) "5"  # 5个商品
    
  4. 删除用户123的购物车中id为3的商品

    127.0.0.1:6379> hdel cart_123 3
    (integer) 1
    

Set

Set 是 String 类型的无序的容器结构。集合成员是唯一的,不能出现重复的数据。

Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

插入集合

sadd key member1 [member2] # 向集合添加一个或多个成员
127.0.0.1:6379> sadd  workers  tom lucy jack
(integer) 3

删除集合

srem key member1 [member2] # 移除集合中一个或多个成员
127.0.0.1:6379> srem workers  tom 
(integer) 1

查询集合

scard key  # 获取集合的成员数
127.0.0.1:6379> scard workers
(integer) 3
smembers key  # 返回集合中的所有成员
127.0.0.1:6379> smembers workers
1) "tom"
2) "jack"
sismember workers tom  # 判断是否集合中的成员

Set类型的练习

  1. 选中用户123 购物车中id为3的商品

    127.0.0.1:6379> sadd cart_selected_123 3
    (integer) 1
    
  2. 取消选中用户123 购物车中id为3的商品

    127.0.0.1:6379> srem cart_selected_123 3
    (integer) 1
    
  3. 查询用户123购物车中所有选中的商品

    127.0.0.1:6379> smembers cart_selected_123
    1) "3"
    
  4. 查询用户123购物车中所有选中的商品个数

    127.0.0.1:6379> scard cart_selected_123
    (integer) 1
    

Zset

它是 String 类型元素的有序集合,每个元素唯一且都会关联一个 double 类型的分值,根据分值来为集合中的成员从小到大排序。

插入有序集合

# zadd key score1 member1 [score2 member2]  # 向有序集合添加一个或多个成员,或者更新已存在成员的分数
127.0.0.1:6379> zadd salary 10000 Jim 8000 Tom 12000 JiMi 10000 Hake
(integer) 1

删除有序集合

zrem key member [member ...]  # 移除有序集合中的一个或多个成员
127.0.0.1:6379> zrem salary Hake  # 删除员工Hake
(integer) 1

# zremrangebyrank key start stop  # 根据排名区间【0,3】 删除成员
127.0.0.1:6379> zremrangebyrank salary 1 2
(integer) 2
127.0.0.1:6379> zrange salary 0 -1
1) "dandan"

zremrangebyscore key min max  # 根据分数区间【10,30】删除成员
127.0.0.1:6379> zremrangebyscore salary 10 30
(integer) 2
127.0.0.1:6379> zrange salary 0 -1
1) "liuyang"
2) "dandan"

更新有序集合

zincrby key increment member  # 对指定成员的分数加上增量 increment
127.0.0.1:6379> zincrby salary 300 Jim  # 给员工Jim涨300元薪资 
"10300"

查询有序集合

zcard key #有序集合的所有成员数
127.0.0.1:6379> zcard salary  # 查询所有成员
(integer) 4

zcount key min max  # 统计在指定分数区间的成员数
127.0.0.1:6379> zcount salary (8000 10000  # 统计所有 8000 < score <= 10000 的成员数量
(integer) 0

zrank key member  # 返回指定成员的排名
127.0.0.1:6379> zrank salary Tom  # 根据分值从小到大排序,从0开始
(integer) 0

zrevrank key member  #分值降序排序后的 排名
127.0.0.1:6379> zrevrank salary Tom  #
(integer) 2

zscore key member  # 返回成员的分数值
127.0.0.1:6379> zscore salary Tom  # 查询Tom的薪资
"8000"

zrange key start stop [WITHSCORES]  # 返回有序集合指定索引区间内的成员
127.0.0.1:6379> zrange salary 0 -1  # 查询所有的员工
1) "Tom"
2) "Jim"
127.0.0.1:6379> zrange salary 0 -1 withscores  # 查询所有员工以及对应得薪资
1) "Tom"
2) "8000"
3) "Jim"
4) "10300"

zrevrange key start stop [WITHSCORES]  # 分值降序后获取索引区间的成员
127.0.0.1:6379> zrevrange salary 0 -1  # 查询所有的员工,按照薪资降序展示
1) "JiMi"
2) "Jim"
3) "Tom"
127.0.0.1:6379> zrevrange salary 0 -1 withscores  # 查询所有员工以及对应得薪资,按照薪资降序展示
1) "JiMi"
2) "12000"
3) "Jim"
4) "10300"
5) "Tom"
6) "8000"

# zrangebyscore key min max [WITHSCORES] [LIMIT]  # 返回指定分数区间内的成员
127.0.0.1:6379> zrangebyscore salary 8000 20000  # 查询 薪资在8000到20000之间的所有员工
1) "Tom"
2) "Hake"
3) "Jim"
4) "JiMi"
# limit 进行分割, 从第二个数据开始
127.0.0.1:6379> zrangebyscore salary 8000 20000 limit 2 1 withscores  #查询 薪资在8000到20000之间的所有员工以及对应的薪资,并对结果分页,每页显示1条数据,第3页
1) "Jim"
2) "10300"

zrevrangebyscore key max min [withscores]  # 返回有序集中指定分数区间内的成员,分数从高到低排序
127.0.0.1:6379> zrevrangebyscore salary 20000 8000  # 查询 薪资在8000到20000之间的所有员工,按照薪资降序展示
1) "JiMi"
2) "Jim"
3) "Tom"
127.0.0.1:6379> zrevrangebyscore salary 20000 8000 limit 2 1 withscores  #查询薪资在8000到20000之间的所有员工以及对应的薪资,按照薪资降序展示,并对结果分页,每页显示1条数据,第3页
1) "Tom"
2) "8000"

Zset练习

  1. 存储所有学生的成绩

    127.0.0.1:6379> zadd score_sheet 30 xue_1 40 xue_2 100 xue_3 87 xue_4
    (integer) 4
    
  2. 查询不及格的学生以及成绩

    127.0.0.1:6379> zrangebyscore score_sheet  0  (60 withscores   # 成绩在 0到 60以下,不包含60
    1) "xue_1"
    2) "30"
    3) "xue_2"
    4) "40"
    
  3. 查询成绩及格的学生数量

    127.0.0.1:6379> zcount score_sheet 60 100
    (integer) 3
    
  4. 查询xue_1的成绩排名

    127.0.0.1:6379> zrevrank score_sheet  xue_1
    (integer) 3
    
  5. 查询所有学生以及成绩,降序展示

    127.0.0.1:6379> zrevrange score_sheet 0 -1 withscores
     1) "xue_3"
     2) "100"
     3) "xue_4"
     4) "87"
     5) "xue_2"
     6) "40"
     7) "xue_1"
     8) "30"
    

    分页
    limit (page-1)*n n: page代表取第几页,n代表每页数量

1-8

第1页 1 2 limit 0 2

第2页 3 4 limit 2 2

第3页 5 6 limit 4 2

第4页 7 8 limit 6 2

作业

利用redis实现以下操作

  1. 将用户admin的图片验证码asd1f6保存到redis中,设置过期时间为3分

    127.0.0.1:6379> set image_code_admin asd1f6 ex 180  # 过期时间需要把3分钟 变成 180秒
    OK
    
  2. 将 用户admin的信息{'username':'admin', 'mobile': 18336078941,'email': 'book@163.com'}进行缓存,以便下次查询

    127.0.0.1:6379> hmset user_info_admin username admin mobile 18336078941 email book@163.com  # 存储个人信息
    (integer) 3
    
    127.0.0.1:6379> hget user_info_admin username  # 查询个人的某一项信息
    "admin"
    127.0.0.1:6379> hget user_info_admin mobile
    "18336078941"
    
    127.0.0.1:6379> hgetall user_info_admin  # 查询所有信息
    1) "username"
    2) "admin"
    3) "mobile"
    4) "18336078941"
    5) "email"
    6) "book@163.com"
    
  3. 保存用户admin在本新闻网站的浏览的id=8的记录

    127.0.0.1:6379> lrem history_admin 0 8  # 先移除所有id为8的新闻的  历史记录
    (integer) 0
    127.0.0.1:6379> lpush history_admin 8  # 在把新闻id添加到 列表的 第一个位置
    (integer) 1
    127.0.0.1:6379> ltrim history_admin 0 9  # 最后,只保留 10条历史记录
    OK
    
  4. 保存用户admin收藏的所有新闻

    # 不考虑收藏顺序,使用 集合
    127.0.0.1:6379> sadd fav_admin 8  # 将新闻id存入 集合中
    (integer) 1
    127.0.0.1:6379> smembers fav_admin  # 获取当前所有收藏的新闻
    1) "8"
    

面试题(写2遍)

1. 简述redis的优缺点?

优点:

内存数据库,读写速度快

支持数据持久化,便于备份、恢复

支持简单的事务

数据类型丰富

支持主从复制,哨兵机制

缺点:
数据存储在内存,容易丢失。
作为缓存时,存在与数据库数据不一致的问题
雪崩问题、缓存击穿问题、缓存并发竞争问题

2. redis常用的数据结构有哪些?

字符串、列表、集合、有序集合、哈希

3. 单线程的redis为什么这么快?

1)纯内存操作

Redis将数据储存在内存里面,读写数据的时候都不会受到硬盘I/O速度的限制,所以速度快

2)单线程操作

单线程可以避免不必要线程间的切换和资源抢占

4. redis的内存淘汰策略有哪些?

1)noeviction(默认策略):当内存满时,写入操作会报错,无法存储新数据。

2)allkeys-lru:当内存满时,移除最近最少使用的key

3)allkeys-random:当内存满时,在键空间中,随机移除某个key
4)volatile-lru,从设置了过期的key中删除最近最少使用的key
5)volatile-random,从设置了过期的key中随机删除key
6)volatile-ttl, 从设置了过期的key中根据剩余过期时间删除。

5. 为什么redis需要把所有的数据放到内存中?

Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘,进行持久化。
如果不将数据放到内存中,磁盘的I/O速度会严重影响Redis的性能。
在内存越来越便宜的今天,Redis将会越来越受欢迎,耗点内存没什么。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值