1、 redis
一、 redis简介
1、什么是redis
1 redis 是一个非关系型数据库(区别于mysql关系型数据库,关联关系,外键,表),nosql数据库(not only sql:不仅仅是SQL),数据完全内存存储(速度非常快)
2 redis就是一个存数据的地方
3 redis是 key--value的存储形式---》value类型有5大数据类型---》字符串,列表,hash(字典),集合,有序集合
redis={ k1:'123', 字符串 k2:[1,2,3,4], 列表/数组 k3:{1,2,3,4} 集合 k4:{name:lqz,age:12} 字典/哈希表 k5:{('lqz',18),('egon',33)} 有序集合 }

1. 使用Redis有哪些好处? (1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) (2) 支持丰富数据类型,支持string,list,set,sorted set,hash (3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 (4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除 2. redis相比memcached有哪些优势? (1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 (2) redis的速度比memcached快很多 (3) redis可以持久化其数据 3. redis常见性能问题和解决方案: (1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件 (2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次 (3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内 (4) 尽量避免在压力很大的主库上增加从库 (5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3... 这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。 4. MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据 相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略: voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰 allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰 allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰 no-enviction(驱逐):禁止驱逐数据 5. Memcache与Redis的区别都有哪些? 1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性。 2)、数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。 3),value大小 redis最大可以达到1GB,而memcache只有1MB 6. Redis 常见的性能问题都有哪些?如何解决? 1).Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。 2).Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。 3).Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。 4). Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内 7, redis 最适合的场景 Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用Redis呢? 如果简单地比较Redis与Memcached的区别,大多数都会得到以下观点: 1 、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。 2 、Redis支持数据的备份,即master-slave模式的数据备份。 3 、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。 (1)、会话缓存(Session Cache) 最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗? 幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。 (2)、全页缓存(FPC) 除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。 再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。 此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。 (3)、队列 Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。 如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。 (4),排行榜/计数器 Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: ZRANGE user_scores 0 10 WITHSCORES Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。 (5)、发布/订阅 最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。 Redis提供的所有特性中,我感觉这个是喜欢的人最少的一个,虽然它为用户提供如果此多功能。
2、 redis的优势和特点
(1) 速度快,因为数据存在内存中,类似于字典,字典的优势就是查找和操作的时间复杂度都是O(1)
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
3、redis的适用场景
redis 最适合的场景就是做缓存,因此它又叫缓存数据库
(1)会话缓存(Session Cache)---》存session---》速度快
(2)接口,页面缓存---》把接口数据,存在redis中
(3)队列--->celery使用
(4)排行榜/计数器--->个人页面访问量
(5)发布/订阅
4、 redis为什么这么快
https://zhuanlan.zhihu.com/p/358163330
1 纯内存操作
2 使用了高性能的网络模型,io多路复用,理论并发量的峰值 10w/s---》6w
项目并发量多少?
指得是1s内能处理的并发请求数,通过多加机器(多进程),多进程,多线程,协程,可以提高并发量
django项目没有开过进程,线程吧,那他如何实现的并发?
1s内10个人访问/index,并不是django框架中在做,而是符合wsgi协议的web服务器做,uwsgi/wsgiref--->这也是为什么项目上线要使用uwsgi,测试阶段使用wsgiref,因为uwsgi并发量高
-django项目的并发量高低取决于,web服务器,uwsgi
-正常业务平均下来,100--200,业务复杂一些 100以内
-双十一,30-40w笔/s
-某个接口的并发量----》1.6w--->麦当劳小程序
-软件指标:用户量:几百万用户,日活月活,几十万的日活----》1s内,同时有多少人在刷某个接口1w多的并发
-你们的项目百级别
补充:其他语言的
java:hashMap 存key-value形式
go:maps 存key-value形式
二、 redis的安装和使用
1、 版本问题
redis最新稳定版版本6.x
win:作者不支持windwos,
本质原因:redis很快,使用了io多路复用中的epoll的网络模型,这个模型不支持win,所以redis不支持win(看到高性能的服务器基本上都是基于io多路复用中的epoll的网络模型,nginx)
微软基于redis源码,自己做了个redis安装包,但是这个安装包最新只到3.x,又有第三方组织做到最新5.x的安装包
2、下载与安装
redis是c语言写的开源软件,官方提供源码,如果是在mac或linux上需要 编译,安装。具体:
mac:安装包---》编译完成的可执行文件---》下一步安装
linux:linux--》make成可执行文件---》make install 安装
win:下载安装包,一路下一步安装
最新5.x版本 https://github.com/tporadowski/redis/releases/
最新3.x版本 https://github.com/microsoftarchive/redis/releases
3、redis的图形化客户端rdb
mysql中有个图形化客户端-Navicat。
redis 也有很多,推荐用rdb
地址:https://github.com/uglide/RedisDesktopManager/releases
收费,99元永久
4、redis服务的启动与关闭
方式一:win上,就在服务中了,把服务开启即可,在服务中启动关闭
方式二:命令启动,等同于mysqld
redis-server redis.windows-service.conf
redis-server 配置文件
5、客户端连接redis
方式一:
命令行:redis-cli -p 端口 -h 地址
或者:redis-cli(常用)
方式二:
客户端 :rdb连接(图形化界面连接)
pip install redis
2、python连接redis
1)普通连接
from redis import Redis # 1 普通连接 conn = Redis(host="localhost", port=6379, db=0, password=None) # 实例化Redis类得到conn对象 conn.set('name', "lqz") # 通过对象调用方法,在redis中存入name为laz的数据 res = conn.get('name') # 取出name print(res) # b'lqz'
2)连接池连接
1.新建py文件redis_pool放置连接池
import redis # 实例化类生成连接池POOL POOL = redis.ConnectionPool(max_connections=10, host='localhost', port=6379)
2.模块导入实现连接池的单例连接
# 2 连接池连接(以模块导入的方式实现单例) import redis from redis_pool import POOL # 导入连接池, # 由于python中无论模块导入多少次,都以第一次导入为准,所以POOL只会是同一个POOL(连接池) conn = redis.Redis(connection_pool=POOL) # 从池中拿一个连接 conn.set('name', "lqz") print(conn.get('name')) # b'lqz'
3)连接池多线程演示
1.新建py文件redis_pool放置连接池
import redis
# 实例化类生成连接池POOL
POOL = redis.ConnectionPool(max_connections=10, host='localhost', port=6379)
2.for循环多线程演示
# 3 多线程演示 import redis # 导入redis模块 from threading import Thread # 导入线程 import time from redis_pool import POOL # 导入自制连接池 def get_name(): conn = redis.Redis(connection_pool=POOL) print(conn.get('name')) for i in range(10): t = Thread(target=get_name) t.start() time.sleep(2) # 十个 b'lqz'
补充1:pycharm导入爆红/执行文件不能使用相对导入
1 py作为脚本运行,不能使用相对导入
2 只能使用绝对导入
3 从环境变量中开始到导起,要遵循最短路径导入
4 在pycharm中右键运行的脚本所在的目录,就会被加入到环境变量
补充2:django中没有连接池
django中一个请求就会创建一个mysql连接,但是django并发量不高,所以mysql数据库能撑住,
想在django中使用连接池,有第三方:https://www.cnblogs.com/wangruixing/p/13030755.html
四、redis操作

""" 数据操作:字符串、列表、哈希(字典)、无序集合、有序(排序)集合 有序集合:游戏排行榜 字符串: set key value get key mset k1 v1 k2 v2 ... mget k1 k2 ... setex key exp value incrby key increment 列表: rpush key value1 value2 ... lpush key value1 value2 ... lrange key bindex eindex lindex key index lpop key | rpop key linsert key before|after old_value new_value 哈希: hset key field value hget key field hmset key field1 value1 field2 value2 ... hmget key field1 field2 hkeys key hvals key hdel key field 集合: sadd key member1 member2 ... sdiff key1 key2 ... sdiffstore newkey key1 key2 ... sinter key1 key2 ... sunion key1 key2 ... smembers key spop key 有序集合: zadd key grade1 member1 grade2 member2 ... zincrby key grade member zrange key start end zrevrange key start end """
1、

import redis conn = redis.Redis() # 1 set(name, value, ex=None, px=None, nx=False, xx=False) # conn.set('age', 19) # 新增age:19 # ex,过期时间(秒)---->过期时间 # px,过期时间(毫秒) ---->过期时间 # conn.set('wife', 'lyf', ex=3) # 3s过期 # nx,如果设置为True,则只有name不存在时,当前set操作才执行, 值存在,就修改不了,执行没效果 # conn.set('wife', 'dlrb', nx=True) # xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值 # conn.set('wife', 'dlrb', xx=True) # 2 setnx(name, value)--->等同于conn.set('wife','dlrb',nx=True) # 3 setex(name, value, time)--->conn.set('wife','lyf',ex=3) # 4 psetex(name, time_ms, value)--->conn.set('wife','lyf',px=3) # 5 mset(*args, **kwargs)--》批量设置 # conn.mset({'name1': 'pyy', 'age1': 20}) # 6 get(name) 取值 # print(conn.get('age1')) # 7 mget(keys, *args) # print(conn.mget(['age1', 'age'])) # print(conn.mget('name', 'age', 'age1')) # 8 getset(name, value) # print(conn.getset('name', 'dsb')) # 它跟get,再set有什么区别? # 9 getrange(key, start, end) # print(conn.getrange('name', 0, 1)) # 取字节 ,前闭后闭 # 10 setrange(name, offset, value) # conn.setrange('name', 1, 'qqq') # dsb--->dqqq # 11 setbit(name, offset, value) ---》后面再聊---》独立用户统计---》用户量过亿---》日活 # conn.setbit('name', 1, 0) # 改的是比特位,d 一个byte占8个比特位--》2进制---》10进制---》字符 # 12 getbit(name, offset) # print(conn.getbit('name', 1)) # 13 bitcount(key, start=None, end=None) # print(conn.bitcount('name', 0, 1)) # 数字指的是字节,不是比特位 # 14 strlen(name) # 字节(一个byte)和字符(中 ? a 都是一个字符) # 面试题:mysql中utf8和utf8mb4有什么区别? # utf8---》不是咱们任务的utf-8,mysql字节的,两个字节表示一个字符---》生僻字,表示存不了 # utf8mb4--》utf-8,最多4个字节表示一个字符---》存标签,存生僻字 # print(conn.strlen('name')) # 字节--》9--》gbk编码一个中文占2个字节 utf-8编码 大部分一个中文占3个字节,生僻字可能占4 # 15 incr(self, name, amount=1)--->做计数器--》记录博客访问量--》博客表的文章上加个访问量字段,一旦有一个人访问,数字+1 # conn.incr('age') # 不存在并发安全的问题---》redis6.0之前是单线程架构,并发访问操作,实际只排着队一个个来 # 16 incrbyfloat(self, name, amount=1.0) # 17 decr(self, name, amount=1) # conn.decr('age') # 18 append(key, value) # conn.append('name','nb')
2、

''' 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) ''' import redis conn=redis.Redis() # 1 hset(name, key, value) # conn.hset("userinfo",'name','彭于晏') # conn.hset("userinfo_01",mapping={'name':"刘亦菲",'age':18}) # 2 hmset(name, mapping)---》弃用了-->直接使用hset即可 # conn.hmset("userinfo_02",mapping={'name':"刘亦菲",'age':18}) # 3 hget(name,key) # print(str(conn.hget('userinfo_01','name'),encoding='utf-8')) # print(str(conn.hget('userinfo_01','age'),encoding='utf-8')) # 4 hmget(name, keys, *args) # print(conn.hmget('userinfo_01',['name','age'])) # print(conn.hmget('userinfo_01','name','age')) # 5 hgetall(name)--->慎用,有可能数据量很大,会撑爆内存-->一般我们redis服务器使用内存很大的服务器,应用服务器内存小一些 # print(conn.hgetall('userinfo_01')) # 6 hlen(name) # print(conn.hlen('userinfo_01')) # 2 # 7 hkeys(name) # print(conn.hkeys('userinfo_01')) # [b'name', b'age'] # 8 hvals(name) # print(conn.hvals('userinfo_01')) # [b'\xe5\x88\x98\xe4\xba\xa6\xe8\x8f\xb2', b'18'] # 9 hexists(name, key) # print(conn.hexists('userinfo_01','name')) # print(conn.hexists('userinfo_01','height')) # 10 hdel(name,*keys) # conn.hdel('userinfo_01','name') # 11 hincrby(name, key, amount=1) # conn.hincrby('userinfo_01','age') # 12 hincrbyfloat(name, key, amount=1.0) # 因为hgetall不安全,有可能数据量过大,所以尽量使用,迭代取值 # 13 hscan(name, cursor=0, match=None, count=None) hash类型无序----》python 字典在3.6以后有序了,如何实现的? # for i in range(1000): # conn.hset('hash_test','id_%s'%i,'鸡蛋%s号'%i) # 分批获取,但是由于没有顺序,返回一个cursor,下次基于这个cursor再继续获取 # res=conn.hscan('hash_test',0,count=20) # print(res) # res=conn.hscan('hash_test',352,count=20) # print(res) # print(len(res[1])) # 14 hscan_iter(name, match=None, count=None) #全取出所有值,分批取,不是一次性全取回来,减小内存占用 # res=conn.hscan_iter('hash_test',count=10) # generator # # print(res) # for item in res: # print(item) # print(conn.hgetall('hash_test')) # hset hget hlen hexists
3、

''' 1 lpush(name,values) 2 lpushx(name,value) 3 llen(name) 4 linsert(name, where, refvalue, value)) 4 r.lset(name, index, value) 5 r.lrem(name, value, num) 6 lpop(name) 7 lindex(name, index) 8 lrange(name, start, end) 9 ltrim(name, start, end) 10 rpoplpush(src, dst) 11 blpop(keys, timeout) 12 brpoplpush(src, dst, timeout=0) ''' import redis conn=redis.Redis() # 1 lpush(name,values) # conn.lpush('girls','lyf','dlrb') # 图形界面看到的 上面是左, 下面是右 # conn.rpush('girls','杨颖') # 2 lpushx(name,value) 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边 # conn.lpushx('girls','杨颖1') # conn.lpushx('girl','杨颖1') # 3 llen(name) # print(conn.llen('girls')) # 4 linsert(name, where, refvalue, value)) # conn.linsert('girls','before','lyf','张杰') # conn.linsert('girls','after','lyf','lqz') # 4 r.lset(name, index, value) 对name对应的list中的某一个索引位置重新赋值 # conn.lset('girls',1,'lqz') # 5 r.lrem(name, count,value) # conn.lrem('girls',1,'lqz') # 从左侧删第一个 # conn.lrem('girls',-1,'lqz') # 从右侧删第一个 # conn.lrem('girls',0,'lqz') # 全删 # 6 lpop(name) # res=conn.lpop('girls') # print(res) # r=b'\xe6\x9d\xa8\xe9\xa2\x961' # print(str(r,encoding='utf-8')) # 7 lindex(name, index) # print(conn.lindex('girls',1)) # 8 lrange(name, start, end) # print(conn.lrange('girls',0,1)) # 前闭后闭 # 9 ltrim(name, start, end) ---》修剪,只保留起始到终止 # conn.ltrim('girls',1,2) # 10 rpoplpush(src, dst) # 从第一个列表的右侧弹出,放入第二个列表的左侧 # 11 blpop(keys, timeout) # 阻塞式弹出--》可以做消息队列 -->block-->如果没有值,会一直阻塞 # 作用,可以实现分布式的系统---》分布式爬虫 # 爬网页,解析数据,存入数据库一条龙,一个程序做 # 写一个程序,专门爬网页---》中间通过redis的列表做中转 # 再写一个程序专门解析网页存入数据库 # print(conn.blpop('girls',timeout=1)) # 12 brpoplpush(src, dst, timeout=0) # lpush lpop linsert llen blpop
4、

''' delete(*names) exists(name) keys(pattern='*') expire(name ,time) rename(src, dst) move(name, db)) randomkey() type(name) ''' import redis conn=redis.Redis() # delete(*names) # conn.delete('name','name1','hash1') # exists(name) # print(conn.delete('name')) # print(conn.delete('age')) # keys(pattern='*') # 打印所有key * 和 ? # print(conn.keys()) # print(conn.keys('us*')) # print(conn.keys('age?')) # expire(name ,time) # conn.expire('age',3) # rename(src, dst) # conn.rename('wife','girl') # move(name, db)) # conn.move('girl',3) # randomkey() # 随机返回一个key # print(conn.randomkey()) # type(name) # print(conn.type('age1')) # print(conn.type('userinfo'))
5、通过管道实现事务
redis本身是不支持事务的,但是有的时候我们要实现类似这种功能:张三-100块钱,李四+100块钱
通过管道可以实现类似事物的功能:把多次操作的命令放到一个管道中,一次性执行,要么都执行了,要么都不执行
import redis pool = redis.ConnectionPool() # 创建连接池 conn = redis.Redis(connection_pool=pool) # 连接连接池 pipe = conn.pipeline(transaction=True) # 创建事务 pipe.multi() # 连接事务 # 以后用pipe代替conn操作 pipe.set('name', 'lqz') # raise Exception('asdfasdf') # 如果此处抛出异常,name和role都不会执行,反之都会执行 pipe.set('role', 'nb') # 只是往管道中放了命令,还没执行 pipe.execute() # 一次性执行多条命令
五、
方式一:使用连接池
1.util文件夹中新建pool.py文件,存放连接池
import redis POOL = redis.ConnectionPool(max_connections=10, host='localhost', port=6379)
2.django中任意位置导入使用
# 测试视图 class TestView(APIView): def get(self, request): import redis from utils.pool import POOL conn = redis.Redis(connection_pool=POOL) print(conn.get('age')) # b'19' return Response('ok')
方式二:使用第三方 djagno-redis
1、安装
pip install django-redis
2、在项目配置文件中
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} # "PASSWORD": "123", } } }
3、在需要位置使用
from django_redis import get_redis_connection class TestView(APIView): def get(self, request): # 使用django配置的redis conn = get_redis_connection() print(conn.get('name')) # 这种方式django的缓存可以缓存到redis中,以后推荐直接这种方式 cache.set('asdfasd', 'asdfas') # 缓存到redis cache.set('wife', ['dlrb', 'lyf']) # value值可以放任意数据类型 return Response('ok')
4、补充
# 1、一旦这么配置了,以后django的缓存也缓存到reids中了 cache.set('asdfasd','asdfas') # 2、以后在django中,不用使用redis拿连接操作了,直接用cache做就可以了
# 3、不需要关注设置的值类型是什么 cache.set('wife',['dlrb','lyf']) # value值可以放任意数据类型
# 4、底层原理,把value通过pickle转成二进制,以redis字符串的形式存到了redis中
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通