redis五大数据类型
复习
# 1 对腾讯云短信二次封装
-v2
-v3
里面res_dict = json.loads(resp.to_json_string(indent=2)) 我们判断的是list所以需要这么改一下
-API是接口
sdk软件开发工具包 也可以说封装了api
# 2 发送验证码功能
-设置缓存
-django内置
-单页面做缓存(混合开发)
-页面中某个位置
-全站使用缓存
-给某个对象设置缓存 cache.set(key,对象)
# 3 短信登录接口
-返回格式要跟多方式登录统一起来
# 4 短信注册
# 5 前端登录,发送短信
-前端存储数据的地方
-localStorage.setItem('name', 'lqz')
-sessionStorage.setItem('name', 'pyy')
-this.$cookies.set
-node models 删除后在自己机器生成
-项目路径下:cnpm install
redis简单操作
1 注册功能,前端调用后端接口,发给后端用户名 验证码密码
send_sms() {
if (!this.is_send) return;
this.is_send = false;
let sms_interval_time = 60;
this.sms_interval = "发送中...";
let timer = setInterval(() => {
if (sms_interval_time <= 1) {
clearInterval(timer);
this.sms_interval = "获取验证码";
this.is_send = true; // 重新回复点击发送功能的条件
} else {
sms_interval_time -= 1;
this.sms_interval = `${sms_interval_time}秒后再发`;
}
}, 1000);
this.$axios.get(this.$settings.base_url + 'user/userinfo/send_sms/?phone=' + this.mobile).then(res => {
if (res.data.code == 100) {
this.$message({
message: '发送成功',
type: 'success'
});
} else {
this.$message({
message: '发送失败,请稍后再试',
type: 'error'
});
}
})
},
register_btn() {
if (this.mobile && this.sms && this.password) {
// 发送axios请求
this.$axios.post(this.$settings.base_url + 'user/register/',
{'mobile': this.mobile, 'password': this.password, 'code': this.sms}).then(res => {
if (res.data.code == 100) {
this.$message({
message: '注册成功',
type: 'success'
});
// 关闭模态框
this.$emit("close")
} else {
this.$message({
message: '注册失败,请联系系统管理员',
type: 'error'
});
}
})
} else {
this.$message({
message: '手机号或密码或验证码不能为空',
type: 'warning'
});
}
}
md5加密
import hashlib
#加密
md5=hashlib.md5()
md5.update(b'zhang111')
res= md5.hexdigest()
print(res)
2 redis介绍和安装
1.关系型数据库
# 具有固定的表结构 并且表与表之间可以通过外键建立关系
MySQL、MariaDB、Oracle、PostgreSQL、sqlserver、sqlite、db2
2.非关系型数据库
# 没有固定的表结构 数据存储采用K:V键值对的形式
redis、mongoDB、memcache
# redis是:数据库,非关系型数据库,也叫nosql数据库(Not Only SQL)
-key-value形式存储,
#5大数据类型:字符串,列表,字典(hash),集合,有序集合
-纯内存,存取都在内存,速度很快 10w实际没这么高 qps,6w左右
-redis特点:
-可以持久化,可以永久存储,存到硬盘上
-单线程,单进程, 6.x之前是, 6.x之后是多线程
面试-为什么redis单线程架构还这么快?
-纯内存操作,内存块
-单线程,单进程架构,不存在线程,进程间切换造成的浪费(6.x没有了)
-高效的网络模型--》IO多路复用 (IO模型,select和epoll的区别)
-http://liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/25-IO%E6%A8%A1%E5%9E%8B/
# redis和Memcached
相同点-都是内存操作,速度都很快,基本都用来做缓存
不同点-reids支持持久化,Memcached只支持字符串,不支持其他类型
# 安装:
-开源软件,意大利,C写的,初期代码只有1w多行
-使用了IO多路复用的:epoll模型,epoll不支持win,
-微软官方给支持:https://github.com/MicrosoftArchive/redis/releases
-第三方:https://github.com/tporadowski/redis/releases
-win一路下一步,做成服务
-mac和linux都是编译安装
-端口:6379
-官方地址 www.redis.cn 中文
www.redis.io英文
-安装时 记得选自动添加到环境变量,还有加入防火墙
# redis 启动和停止
-win:启动服务和停止服务即可
-任意路径敲:redis-server 就可以启动服务
-带配置文件启动:redis-service redis.windows-service.conf
# 可执行文件
redis-server:启动服务 类似于 mysqld
redis-cli:客户端命令 类似于 mysql
# redis-desktop-manager-0.9.3.817 类似于Navicate 连接redis用的
-原来开源免费,后来收费了
-目前来说,只能用我这个
3 Python操作redis和连接池
3.1 普通链接
# python 操作redis
# pip install redis
# 第一步:导入 Redis类
from redis import Redis
# 第二步:创建链接(地址和端口,如果不传就是本地的6379)
conn=Redis(host='127.0.0.1',port=6379)
# 取值
res=conn.get('name')
print(res)
conn.close() # 关闭链接
3.2 连接池******************
POOL.py
import redis
CONN_POOL=redis.ConnectionPool(host='127.0.0.1', port='6379', max_connections=100)
django当中连接mysql是没有连接池的,但是可以设置,需要第三方百度方法很多,但是一般用django不会关注这个因为,django一般是公司内部项目 公司内部使用oython异步框架, 外部一般用go
import redis
conn = redis.Redis()
# 创建连接池 host='127.0.0.1',port='6379'可以不写
# 这个池应该做成单例,以保证整个程序只有这一个对象
# 单例模式:整个全局就这一个实例 实现了全局只用这一个实例
# 以模块导入,天然单例,相对导入以脚本执行此文件会报错,所以要绝对导入,当前文件所在文件夹已经在环境变量里面了
# 所以直接导入就可以,报错是因为pycharm,可以把这个文件夹source root
from POOL import CONN_POOL
# 在连接池拿一个连接
conn = redis.Redis(connection_pool=CONN_POOL)
print(conn.get('name'))
# 把连接放回连接池
conn.close()
4 redis字符串操作
# 用的多:常用操作
'''
## 常用操作
1 set(name, value, ex=None, px=None, nx=False, xx=False)
2 setnx(name, value)
3 get(name)
4 mget(keys, *args)
5 getset(name, value)
6 getrange(key, start, end)
7 setrange(name, offset, value)
8 setbit(name, offset, value)
9 getbit(name, offset)
10 bitcount(key, start=None, end=None)
11 bitop(operation, dest, *keys)
12 strlen(name)
13 incr(self, name, amount=1)
14 incrbyfloat(self, name, amount=1.0)
15 decr(self, name, amount=1)
16 append(key, value)
'''
from redis import Redis
conn=Redis()
# 1 set(name, value, ex=None, px=None, nx=False, xx=False) #设置值
# conn.set('hobby','篮球',ex=3)
# conn.set('hobby','pp',nx=True) # 没有,放能放进去,如果有,不会修改掉原来的
# conn.set('hobby1','pp',xx=True) # 没有,放能放进去,如果有,不会修改掉原来的
'''
ex,过期时间(秒)
px,过期时间(毫秒)
# 用redis做分布式锁
nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
'''
#2 setnx 就是set 但是nx=True #设置值 不存在执行此操作 等同于set nx=true
# conn.setnx('hobby','oooo')
# 3 get(name) --->bytes格式 #获取值
# res=conn.get('hobby')
# 4 mget(keys, *args) #批量获取
# res=conn.mget(keys=['name','age','hobby'])
# res=conn.mget('name','age','hobby')
# 5 getset(name, value)
# res=conn.getset('name','彭于晏')
#设置新值并获取原来的值 效率高
#6 getrange(key, start, end) 前闭后闭区间 ----》字节还是字符?字节
# res=str(conn.getrange('name',0,3),encoding='utf-8')
# res=conn.getrange('name',0,2).decode('utf-8')
#获取子序列(根据字节获取,非字符)
# 参数:
# name,Redis 的 name
# start,起始位置(字节)
# end,结束位置(字节)
# 7 setrange(name, offset, value)
# conn.setrange('name',1,'lqz')
#修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
# 参数:
# offset,字符串的索引,字节(一个汉字三个字节)
# value,要设置的值
# 8 setbit(name, offset, value) 不需要
# res=conn.getbit('name',1)
# conn.setbit('name',1,0)
# 对name对应值的二进制表示的位进行操作
# 参数:
# name,redis的name
# offset,位的索引(将值变换成二进制后再进行索引)
# value,值只能是 1 或 0
# 9 getbit(name, offset)
# 获取name对应的值的二进制表示中的某位的值 (0或1)
# 10 bitcount(key, start=None, end=None)
# 获取name对应的值的二进制表示中 1 的个数
# 参数:
# key,Redis的name
# start,位起始位置
# end,位结束位置
# 12 strlen(name) 字节长度 # 返回name对应值的字节长度(一个汉字3个字节)
# res=conn.strlen('name')
# 13 incr(self, name, amount=1) 自增,统计网站,文章,课程访问量
# conn.incr('age')
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(必须是整数)
# 14 incrbyfloat(self, name, amount=1.0)
# conn.incrbyfloat('age',8.9)
# 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
# 参数:
# name,Redis的name
# amount,自增数(浮点型)
# 15 decr(self, name, amount=1)
# conn.decr('age')
# 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
# 参数:
# name,Redis的name
# amount,自减数(整数)
# 16 append(key, value)
conn.append('age','nb')
# 在redis name对应的值后面追加内容
# 参数:
key, redis的name
value, 要追加的字符串
# print(res)
conn.close()
''''
需要记住的
get 获取
set 设置
strlen 字节长度
append 在末尾追加
'''
5 redis列表操作
'''
1 lpush(name,values)
# 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
# 如:
# r.lpush('oo', 11,22,33)
# 保存顺序为: 33,22,11
# 扩展:
# rpush(name, values) 表示从右向左操作
2 lpushx(name,value)
# 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
# 更多:
# rpushx(name, value) 表示从右向左操作
3 llen(name)# name对应的list元素的个数
4 linsert(name, where, refvalue, value))
# 在name对应的列表的某一个值前或后插入一个新值
# 参数:
# name,redis的name
# where,BEFORE或AFTER(小写也可以)
# refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
# value,要插入的数据
4 lrem(name, value, num)
# 在name对应的list中删除指定的值
# 参数:
# name,redis的name
# value,要删除的值
# num, num=0,删除列表中所有的指定值;
# num=2,从前到后,删除2个;
# num=-2,从后向前,删除2个
6 lpop(name)
# 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
# 更多:
# rpop(name) 表示从右向左操作
7 lindex(name, index) 在name对应的列表中根据索引获取列表元素
8 lrange(name, start, end)
# 在name对应的列表分片获取数据
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置 print(re.lrange('aa',0,re.llen('aa')))
9 ltrim(name, start, end)
# 在name对应的列表中移除没有在start-end索引之间的值
# 参数:
# name,redis的name
# start,索引的起始位置
# end,索引结束位置(大于列表长度,则代表不移除任何)
10 rpoplpush(src, dst)
# 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
# 参数:
# src,要取数据的列表的name
# dst,要添加数据的列表的name
11 blpop(keys, timeout)
# 将多个列表排列,按照从左到右去pop对应列表的元素
# 参数:
# keys,redis的name的集合
# timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞
# 更多:
# r.brpop(keys, timeout),从右向左获取数据
爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值,但是只能一台机器运行取值,可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式
12brpoplpush(src, dst, timeout=0)
# 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
# 参数:
# src,取出并要移除元素的列表对应的name
# dst,要插入元素的列表对应的name
# timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
'''
from redis import Redis
conn=Redis()
# 1 lpush(name,values) # 从列表左侧插入值
# conn.lpush('list1','小明')
# conn.lpush('list1','小红')
# conn.lpush('list1','小张')
# conn.rpush('list1','小方')
# 2 lpushx(name,value) # name值存在才能插入,否则无变化
# conn.lpushx('list2','小刚')
# conn.lpushx('list1','小刚')
# 3 llen(name) # 列表长度
# res=conn.llen('list1')
# 4 linsert(name, where, refvalue, value))
'''
# name,redis的name
# where,BEFORE或AFTER(小写也可以)
# refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
# value,要插入的数据
'''
# res=conn.linsert('list1','before','小红','lqz') # 有重复的,左侧开始第一个
# 4 lrem(name, count, value)
'''
num=0,删除列表中所有的指定值;
num=2,从前到后,删除2个;
num=-2,从后向前,删除2个
'''
# res=conn.lrem('list1','-2','小红')
# lset(name, index, value) 该某个位置的值,从0开始
# conn.lset('list1',0,'刘德华')
# 6 lpop(name) # 从左侧弹出
# res=conn.lpop('list1')
# res=conn.rpop('list1')
# 7 lindex(name, index)
# res=conn.lindex('list1',1)
# 8 lrange(name, start, end)
# res=conn.lrange('list1',0,2) # 前闭后闭
# 9 ltrim(name, start, end)
# res=conn.ltrim('list1',1,10) # 只留这部分
# 10 rpoplpush(src, dst)
# conn.lpush('list2','lqz')
# conn.rpoplpush('list1','list2')
# 11 blpop(keys, timeout) # 如果列表中没有值,会卡在这等着,直到有值,等待多长时间
res=conn.blpop('list2',50)
print(res)
# 12brpoplpush(src, dst, timeout=0)
# print(res)
conn.close()
'''
lpush 左侧插入值
lpop 左侧弹出
llen 列表长度
lset 该某个位置的值,从0开始
blpop # 将多个列表排列,按照从左到右去pop对应列表的元素
'''
6 redis字典操作
# hash:冲突后解决方法
-开放定址法
-线性探测再散列
-再哈希法
-链地址法
'''
1 hset(name, key, value)
# hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
2 hmset(name, mapping)
3 hget(name,key)
4 hgetall(name)
5 hkeys(name)
6 hvals(name)
7 hexists(name, key)
8 hdel(name,*keys)
9 hincrby(name, key, amount=1)
10 hincrbyfloat(name, key, amount=1.0)
11 hscan(name, cursor=0, match=None, count=None)
12 hscan_iter(name, match=None, count=None)
'''
from redis import Redis
conn = Redis()
# 1 hset(name, key, value)
# conn.hset('wife', 'name', '刘亦菲')
# conn.hset('wife', 'age', 34)
# conn.hset('wife', 'height', 167)
# name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
# 参数:
# name,redis的name
# key,name对应的hash中的key
# value,name对应的hash中的value
# 注:
# hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
# 2 hmset(name, mapping)
# conn.hmset('userinfo',{'name':'lqz','age':19})
# 在name对应的hash中批量设置键值对
# 参数:
# name,redis的name
# mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
# 如:
# r.hmset('xx', {'k1':'v1', 'k2': 'v2'})
# 3 hget(name,key) # 在name对应的hash中获取根据key获取value
# res=conn.hget('userinfo','age')
# 4 hgetall(name)# 获取name对应hash的所有键值
# res=type(conn.hgetall('userinfo'))
# res=conn.hgetall('userinfo')[b'age']
# 5 hkeys(name)# 获取name对应的hash中所有的key的值
# res=conn.hkeys('userinfo')
# 6 hvals(name)# 获取name对应的hash中所有的value的值
# res=conn.hvals('userinfo')
# 7 hexists(name, key)# 检查name对应的hash是否存在当前传入的key
# res=conn.hexists('userinfo','age')
# 8 hdel(name,*keys)# 将name对应的hash中指定key的键值对删除
# res=conn.hdel('userinfo','wife')
# res=conn.hdel('wife','name','age','xx')
# 9 hincrby(name, key, amount=1)
# res=conn.hincrby('wife','height')
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(整数)
# 10 hincrbyfloat(name, key, amount=1.0)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 参数:
# name,redis中的name
# key, hash对应的key
# amount,自增数(浮点数)
# 自增name对应的hash中的指定key的值,不存在则创建key=amount
# 11 hscan(name, cursor=0, match=None, count=None)
# https://www.cnblogs.com/xieqiankun/p/python_dict.html
# for i in range(1000):
# conn.hset('test1', 'test_%s' % i, '鸡蛋%s号' % i)
# 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
# 参数:
# name,redis的name
# cursor,游标(基于游标分批取获取数据)
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# res=conn.hscan('test1',cursor=0,count=11)
# res=conn.hscan('test1',cursor=0,count=22)
# print(res)
# print(len(res[1]))
# res=conn.hscan('test1',cursor=32,count=11)
# print(res)
# print(len(res[1]))
# 12 hscan_iter(name, match=None, count=None)
# 获取所有,hgetall,它是分批获取
# res=conn.hscan_iter('test1',count=100) # generator
# print(res)
# for i in res:
# print(i)
#利用yield封装hscan创建生成器,实现分批去redis中获取数据
# 参数:
# match,匹配指定key,默认None 表示所有的key
# count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
# print(res)
conn.close()
'''
重要的
hset 设置值
hget 获取值
hmset 批量设置键值对
hmget 批量获取
hexists 检查name对应的hash是否存在当前传入的key
'''
7 通用操作
'''
1 delete(*names)# 根据删除redis中的任意数据类型
2 exists(name)# 检测redis的name是否存在
3 keys(pattern='*')# 检测redis的name是否存在
# 比如:
# KEYS * 匹配数据库中所有 key 。
# KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
# KEYS h*llo 匹配 hllo 和 heeeeello 等。
# KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo
4 expire(name ,time)# 为某个redis的某个name设置超时时间
5 rename(src, dst)# 对redis的name重命名为
6 move(name, db))# 将redis的某个值移动到指定的db下
7 randomkey()# 随机获取一个redis的name(不删除)
8 type(name)# 获取name对应值的类型
'''
from redis import Redis
conn=Redis()
# 1 delete(*names)
# conn.delete('hobby')
# # 根据删除redis中的任意数据类型
# 2 exists(name)
# res=conn.exists('list1','test1')
# print(res)
# # 检测redis的name是否存在 *表示多个字符 ? 表示一个字符
# 3 keys(pattern='*')
# res=conn.keys(pattern='l*')
# res=conn.keys(pattern='lis?')
# print(res)
# 4 expire(name ,time)
# conn.expire('list1',3)
# 5 rename(src, dst)
# conn.rename('test1','test2')
# 6 move(name, db))
# conn.move('test2',1)
# 7 randomkey() # 随机取一个key值,不删除
# res=conn.randomkey()
# print(res)
# 8 type(name)
res=conn.type('userinfo')
print(res)