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)

posted @ 2022-02-26 20:08  迪迦张  阅读(141)  评论(0编辑  收藏  举报