redis
1 redis介绍
# 介绍 c s 架构的软件 redis:非关系型数据库【存数据的地方】nosql数据库,内存存储,速度非常快,可以持久化【数据从内存同步到硬盘】,数据类型丰富【5大数据类型:字符串,列表,哈希(字典),集合,有序集合】,key-value形式存储【根本没有表的结构,相当于咱们的字典】 -nosql:指非关系型数据库:1 不限于SQL 2 没有sql # redis 为什么这么快 -1 高性能的网络模型:IO多路复用的epoll模型,承载住非常高的并发量 -2 纯内存操作,避免了很多io -3 单线程架构,避免了线程间切换的消耗 -6.x之前:单线程,单进程 -6.x以后,多线程架构,数据操作还是使用单线程,别的线程做数据持久化,其他操作 # redis 应用场景(了解) 1 当缓存数据库使用,接口缓存,提高接口响应速度 -请求进到视图---》去数据查询[多表查询,去硬盘取数据:速度慢]----》转成json格式字符串---》返回给前端 -请求进到视图---》去redis[内存]----》取json格式字符串---》返回给前端 2 做计数器:单线程,不存在并发安全问题 -统计网站访问量 -个人站点浏览量 -文章阅读量 3 去重操作:集合 4 排行榜:有序集合 -阅读排行榜 -游戏金币排行榜 5 布隆过滤器 6 抽奖 7 消息队列
1.1 redis安装
# 开源软件:使用c语言写的---【编译型语言,在操作系统运行,要编译成可执行文件,由于采用了IO多路复用的epoll模型,所以它不支持windows,只有linux操作系统支持epoll】 # 微软官方:改了,编译成可执行的安装包,下载一路下一步安装 -版本没有最新 # 官网:https://redis.io/ -下载完是源代码:c语言源码 :https://redis.io/download/#redis-stack-downloads -最稳定:6.x -最新7.x # 中文网:http://redis.cn/download.html -上面最新只到5.x # win版本下载地址 # 最新5.x版本 https://github.com/tporadowski/redis/releases/ # 最新3.x版本 https://github.com/microsoftarchive/redis/releases 下载完一路下一步即可,具体可参照:https://www.cnblogs.com/liuqingzheng/p/9831331.html # win装完会有redis服务 -启动服务,手动停止 -客户端链接:redis-cli -h 127.0.0.1 -p 6379 -简单命令: set name lqz get name ping -停掉服务: -去win服务点关闭 -客户端关闭:shutdown #mysql 服务端 #mysql客户端 -navicate -命令窗口cmd -python操作 # redis 服务器端 # redis 客户端 -redis-cli -图形化工具:redis-destop-management -python操作
2 python操作redis
# pip3 install redis from redis import Redis conn=Redis( host="localhost",port=6379) # conn.set('name','xxx') print(conn.get('name')) conn.close()
3 redis连接池
POOL.py import redis pool = redis.ConnectionPool(max_connections=200, host='127.0.0.1', port=6379)
from redis import Redis from threading import Thread # 直接链接 # def get_name_from_redis(): # conn = Redis(host="localhost", port=6379) # print(conn.get('name')) # conn.close() # # # for i in range(100): # t=Thread(target=get_name_from_redis) # t.start() # # # import time # time.sleep(10) ### 使用连接池链接 import redis from POOL import pool def get_name_from_redis(): # 创建一个连接池,保证它是单例,全局只有一个pool对象:使用模块导入方式实现单例 conn = redis.Redis(connection_pool=pool) #m每执行一次会从池中取一个链接,如果没有,等待 res=conn.get('name') print(res) conn.close() for i in range(100): t=Thread(target=get_name_from_redis) t.start()
4 redis操作字符串
# redis有5大数据类型---》字符串,hash,列表 # 主要的api:操作字符串的方法 ''' 1 set(name, value, ex=None, px=None, nx=False, xx=False) 2 setnx(name, value) 3 psetex(name, time_ms, value) 4 mset(*args, **kwargs) 4 get(name) 5 mget(keys, *args) 6 getset(name, value) 7 getrange(key, start, end) 8 setrange(name, offset, value) 9 setbit(name, offset, value) 10 getbit(name, offset) 11 bitcount(key, start=None, end=None) 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) ''' # 记住的:get set strlen
import redis conn = redis.Redis() # 1 set(name, value, ex=None, px=None, nx=False, xx=False) # ex,过期时间(秒) # px,过期时间(毫秒) # nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果 # xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值 # conn.set('name','lqz') # value 只能是字符串或byte格式 # conn.set('name','lqz',ex=3) # ex 是过期时间,到3s过期,数据就没了 # conn.set('name','lqz',px=3000) # px 是过期时间,到3s过期,数据就没了 # conn.set('age',25,nx=True) # redis 实现分布式锁:https://zhuanlan.zhihu.com/p/489305763 # conn.set('hobby', '足球', xx=False) # 2 setnx(name, value) 就是:set nx=True # conn.setnx('hobby1','橄榄球') # 3 psetex(name, time_ms, value) 本质就是 set px设置时间 # conn.psetex('name',3000,'lqz') # 4 mset(*args, **kwargs) 传字典批量设置 # conn.mset({'name':'xxx','age':19}) # 5 get(name) 获取值,取到是bytes格式 ,指定:decode_responses=True,就完成转换 # print(conn.get('name')) # print(str(conn.get('name')[:3],encoding='utf-8')) # 5 mget(keys, *args) #批量获取 # res=conn.mget('name','age') # res=conn.mget(['name','age']) # print(res) # 6 getset(name, value) # 先获取,再设置 # res=conn.getset('name','lqz') # print(res) # 7 getrange(key, start, end) # 取的是字节,前闭后闭区间 # res=conn.getrange('name',0,1) # print(res) # 8 setrange(name, offset, value) # 从某个起始位置开始替换字符串 # conn.setrange('name', 1, 'xxx') # 9 setbit(name, offset, value) # conn.setbit('name',1,0) #lqz 00000000 00000000 00000000 # res=conn.get('name') # print(res) # 10 getbit(name, offset) # res=conn.getbit('name',1) # print(res) # 11 bitcount(key, start=None, end=None) # print(conn.bitcount('name',0,3)) # 3 指的是3个字符 # 12 strlen(name) # 统计字节长度 # print(conn.strlen('name')) # print(len('lqz政')) # len 统计字符长度 # 13 incr(self, name, amount=1) # 计数器 # conn.incr('age',amount=3) # 14 incrbyfloat(self, name, amount=1.0) # 15 decr(self, name, amount=1) # conn.decr('age') # 16 append(key, value) conn.append('name','nb') conn.close()
5
''' 1 hset(name, key, value) 2 hmset(name, mapping) 3 hget(name,key) 4 hmget(name, keys, *args) 5 hgetall(name) 6 hlen(name) 7 hkeys(name) 8 hvals(name) 9 hexists(name, key) 10 hdel(name,*keys) 11 hincrby(name, key, amount=1) 12 hincrbyfloat(name, key, amount=1.0) 13 hscan(name, cursor=0, match=None, count=None) 14 hscan_iter(name, match=None, count=None) ''' 记住:hset hget hexists hincrby hlen
### redis 只支持一层的5大数据类型 import redis conn = redis.Redis(decode_responses=True) # 1 hset(name, key, value) # conn.hset('userinfo', 'name', '彭于晏') # conn.hset('userinfo', 'age', '32') # conn.hset('xx',mapping={'name':'xxx','hobby':'篮球'}) # 2 hmset(name, mapping) 弃用了 # conn.hmset('yy',{'a':'a','b':'b'}) # 3 hget(name,key) # res=conn.hget('userinfo','age') # print(res) # 4 hmget(name, keys, *args) # res=conn.hmget('userinfo',['name','age']) # print(res) # 5 hgetall(name) 慎用,可能会造成 阻塞 尽量不要在生产代码中执行它 # res=conn.hgetall('userinfo') # print(res) # 6 hlen(name) # res=conn.hlen('userinfo') # print(res) # 7 hkeys(name) # res=conn.hkeys('userinfo') # print(res) # 8 hvals(name) # res=conn.hvals('userinfo') # print(res) # 9 hexists(name, key) # res=conn.hexists('userinfo','name') # print(res) # 10 hdel(name,*keys) # conn.hdel('userinfo','age') # 11 hincrby(name, key, amount=1) # conn.hincrby('userinfo','age') # 12 hincrbyfloat(name, key, amount=1.0) # conn.hincrbyfloat('userinfo','age',5.44) ## 联合起来讲:不建议使用hgetall,分片取值 # 分批获取 生成器应用在哪了? # 13 hscan(name, cursor=0, match=None, count=None) # hash类型没有顺序---》python字典 之前没有顺序,3.6后有序了 python字段的底层实现 # for i in range(1000): # conn.hset('test_hash','key_%s'%i,'鸡蛋%s号'%i) # count 是要取的条数,但是不准确,有点上下浮动 # 它一般步单独用 # res=conn.hscan('test_hash',cursor=0,count=19) # print(res) # print(res[0]) # print(res[1]) # print(len(res[1])) # res=conn.hscan('test_hash',cursor=res[0],count=19) # print(res) # print(res[0]) # print(res[1]) # print(len(res[1])) # 咱么用它比较多,它内部封装了hscan,做成了生成器,分批取hash类型所有数据 # 14 hscan_iter(name, match=None, count=None) 获取所有hash的数据 res = conn.hscan_iter('test_hash',count=100) print(res) # 生成器 for item in res: print(item) conn.close()
6 redis列表操作
''' 1 lpush(name,values) 2 lpushx(name,value) 3 rpushx(name, value) 表示从右向左操作 4 llen(name) 5 linsert(name, where, refvalue, value)) 6 lset(name, index, value) 7 lrem(name, value, num) 8 lpop(name) 9 lindex(name, index) 10 lrange(name, start, end) 11 ltrim(name, start, end) 12 rpoplpush(src, dst) 13 blpop(keys, timeout) 14 brpoplpush(src, dst, timeout=0) 15 自定义增量迭代 '''
7 管道
# mysql事务:四大特性 事务的隔离级别 mysql5.7 默认的隔离级别是什么 # redis:redis数据库,是否支持事务? -支持 -不支持 # redis事务机制可以保证一致性和隔离性,无法保证持久性,但是对于redis而言,本身是内存数据库,所以持久化不是必须属性。原子性需要自己进行检查,尽可能保证 # redis 不像mysql一样,支持强事务,事务的四大特性不能全部满足,但是能满足一部分,通过redis的管道实现的 # redis本身不支持事务,但是可以通过管道,实现部分事务 # redis 通过管道,来保证命令要么都成功,要么都失败,完成事务的一致性,但是管道只能用在单实例,集群环境中,不支持pipline
import redis conn = redis.Redis() pipline = conn.pipeline(transaction=True) pipline.decr('a', 2) # a减2 raise Exception('我崩了') pipline.incr('b', 2) # b加2 pipline.execute() conn.close()
8 redis其他操作
# 集合,有序集合 --- redis模块提供的方法API # 通用操作:无论是5大类型的那种,都支持 import redis conn = redis.Redis() # 1 delete(*names) # conn.delete('age', 'name') # 2 exists(name) # res=conn.exists('xx') # print(res) # 0 # 3 keys(pattern='*') # res=conn.keys('*o*') # res=conn.keys('?o*') # print(res) # 4 expire(name ,time) # conn.expire('test_hash',3) # 5 rename(src, dst) # 对redis的name重命名为 # conn.rename('xx','xxx') # 6 move(name, db) # 将redis的某个值移动到指定的db下 # 默认操作都是0 库,总共默认有16个库 # conn.move('xxx',2) # 7 randomkey() 随机获取一个redis的name(不删除) # res=conn.randomkey() # print(res) # 8 type(name) 查看类型 # res = conn.type('aa') # list hash set # print(res) conn.close()
9 django中集成redis
# 方式一:直接使用 from user.POOL import pool import redis def index(request): conn = redis.Redis(connection_pool=pool) conn.incr('page_view') res = conn.get('page_view') return HttpResponse('被你看了%s次' % res) # 方式二:使用第三方模块:django-redis -下载 -配置文件配置 CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/0", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "123", } } } -使用 from django_redis import get_redis_connection def index(request): conn = get_redis_connection(alias="default") # 每次从池中取一个链接 conn.incr('page_view') res = conn.get('page_view') return HttpResponse('被你看了%s次' % res) # 方式三:借助于django的缓存使用redis -如果配置文件中配置了 CACHES ,以后django的缓存,数据直接放在redis中 -以后直接使用cache.set 设置值,可以传过期时间 -使用cache.get 获取值 -强大之处在于,可以直接缓存任意的python对象,底层使用pickle实现的
10 redis启动命令
#1 最简启动 redis-server ps -aux|grep redis #查看进程 netstat -antpl|grep redis #查看端口 netstat -nlp |grep 6379 redis-cli -h ip -p port ping #命令查看 # 2 动态参数启动 redis-serve --port 6380 #启动,监听6380端口 # 3 配置文件启动 #查看一下默认注释,把#和空格去掉 cat redis.conf|grep -v "#" |grep -v "^$" #重定向到另一个文件 cat redis.conf|grep -v "#" |grep -v "^$" >redis-6382.conf ''' daemonize yes #是否以守护进程启动 pidfile /var/run/redis.pid #进程号的位置,删除 port 6379 #端口号 dir /opt/soft/redis/data #工作目录 logfile 6379.log #日志位置 #其他全删掉 ''' #在redis目录下新建data目录,用来存放数据 #启动redis redis-server /root/redis/redis.conf #查看进程 ps -ef |grep redis-server |grep 6379 #查看日志 cd data cat 6379.log
10.1 客户端连接(命令)
# redis-cli -h 地址 -p 端口 # 查看所有配置 config get * # 107对 port daemonize logfile dbfilename requirepass # 设置密码 maxmemory # 最大占用内存,0 不限制 databases #16 个库 maxclients appendonly # 持久化 dir slaveof # 复制谁,如果是从库,这个地方要写主库 bind # 修改配置(直接改文件,重启) # 修改配置(客户端直接修改) ---》临时改,当前进程如果不停,生效,重启就没了 CONFIG SET maxmemory 128M CONFIG get maxmemory CONFIG set requirepass 123456 # 永久生效,同步到配置文件中 CONFIG REWRITE # 直接客户端链接,修改配置信息,写到配置文件中 -如果以root用户启动redis,CONFIG REWRITE功能,会导致黑客提权,直接登录到系统中,放挖矿病毒 -避免: -端口跑在别的上,不是6379 -redis密码设置尽量复制 -不用root用户启动redis -启动redis的用户,不允许登录系统ssh链接 ####redis返回值 状态回复:ping---》PONG 错误回复:hget hello field ---》(error)WRONGTYPE Operation against 整数回复:incr hello---》(integer) 1 字符串回复:get hello---》"world" 多行字符串回复:mget hello foo---》"world" "bar"
11 redis通用命令
# 大 O 表示法,衡量算法优劣的标准 -时间复杂度 -空间复杂度 -O(1) 最好的,只需要一次就能拿到结果 -O(log n) n的一半 -O(n) 循环n次 -O(n2) 两层for循环 ####1-keys #打印出所有key keys * #打印出所有以he开头的key keys he* #打印出所有以he开头,第三个字母是h到l的范围 keys he[h-l] #三位长度,以he开头,?表示任意一位 keys he? #keys命令一般不在生产环境中使用,生产环境key很多,时间复杂度为o(n),用scan命令 ####2-dbsize 计算key的总数 dbsize #redis内置了计数器,插入删除值该计数器会更改,所以可以在生产环境使用,时间复杂度是o(1) ###3-exists key 时间复杂度o(1) #设置a set a b #查看a是否存在 exists a (integer) 1 #存在返回1 不存在返回0 ###4-del key 时间复杂度o(1) 删除成功返回1,key不存在返回0 ###5-expire key seconds 时间复杂度o(1) expire name 3 #3s 过期 ttl name #查看name还有多长时间过期 persist name #去掉name的过期时间 ###6-type key 时间复杂度o(1) type name #查看name类型,返回string ### 7 其他 info命令:内存,cpu,主从相关 ,redis监控 - redis-cli auth 123456 info --->返回字符串 subprocess client list 正在连接的会话 client kill ip:端口 dbsize 总共有多少个key flushall 清空所有 flushdb 只清空当前库 select 数字 选择某个库 总共16个库 monitor 记录操作日志,夯住
12 redis 集合
# 无序,无重复,集合间操作(交叉并补) # 常用api sadd key element #向集合key添加element(如果element存在,添加失败) o(1) srem key element #从集合中的element移除掉 o(1) scard key #计算集合大小 sismember key element #判断element是否在集合中 srandmember key count #从集合中随机取出count个元素,不会破坏集合中的元素 spop key #从集合中随机弹出一个元素 smembers key #获取集合中所有元素 ,无序,小心使用,会阻塞住 sdiff user:1:follow user:2:follow #计算user:1:follow和user:2:follow的差集 sinter user:1:follow user:2:follow #计算user:1:follow和user:2:follow的交集 sunion user:1:follow user:2:follow #计算user:1:follow和user:2:follow的并集 sdiff|sinter|suion + store destkey... #将差集,交集,并集结果保存在destkey集合中 # 作用 抽奖系统 :通过spop来弹出用户的id,活动取消,直接删除 点赞,点踩,喜欢等,用户如果点了赞,就把用户id放到该条记录的集合中 标签:给用户/文章等添加标签,sadd user:1:tags 标签1 标签2 标签3 给标签添加用户,关注该标签的人有哪些 共同好友:集合间的操作
13 redis 有序集合
# 不重复,有个分值字段,保证集合有顺序 # 操作 zadd key score element #score可以重复,可以多个同时添加,element不能重复 o(logN) zrem key element #删除元素,可以多个同时删除 o(1) zscore key element #获取元素的分数 o(1) zincrby key increScore element #增加或减少元素的分数 o(1) zcard key #返回元素总个数 o(1) zrank key element #返回element元素的排名(从小到大排) zrange key 0 -1 #返回排名,不带分数 o(log(n)+m) n是元素个数,m是要获取的值 zrange player:rank 0 -1 withscores #返回排名,带分数 zrangebyscore key minScore maxScore #返回指定分数范围内的升序元素 o(log(n)+m) n是元素个数,m是要获取的值 zrangebyscore user:1:ranking 90 210 withscores #获取90分到210分的元素 zcount key minScore maxScore #返回有序集合内在指定分数范围内的个数 o(log(n)+m) zremrangebyrank key start end #删除指定排名内的升序元素 o(log(n)+m) zremrangebyrank user:1:rangking 1 2 #删除升序排名中1到2的元素 zremrangebyscore key minScore maxScore #删除指定分数内的升序元素 o(log(n)+m) zremrangebyscore user:1:ranking 90 210 #删除分数90到210之间的元素 zrevrank #从高到低排序 zrevrange #从高到低排序取一定范围 zrevrangebyscore #返回指定分数范围内的降序元素 zinterstore #对两个有序集合交集 zunionstore #对两个有序集合求并集 # 作用 排行榜:音乐排行榜,销售榜,关注榜,游戏排行榜
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY