27 redis讲解
redis介绍和安装
# 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,在win的支持就不好 -微软官方给支持:https://github.com/MicrosoftArchive/redis/releases #3.x -第三方:https://github.com/tporadowski/redis/releases #5.x -win一路下一步,做成服务 -mac和linux都是编译安装 -端口:6379 # redis 启动和停止 -win:启动服务和停止服务即可 -任意路径敲:redis-server 就可以启动服务 -带配置文件启动:redis-service redis.windows-service.conf # 可执行文件(cmd) redis-server:启动服务 类似于 mysqld 或者执行redis-server.exe redis.windows.conf redis-cli:客户端命令 类似于 mysql # redis-desktop-manager-0.9.3.817 类似于Navicate -原来开源免费,后来收费了 -目前来说,只能用我这个
2 Python操作redis和连接池
pip install redis
#scripts/redis-t.py
# 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() # 关闭链接
import redis CONN_POOL= redis.ConnectionPool(host='127.0.0.1',port=6379, max_connections=100) # 池的大小
#scripts/redis_pool.py
import redis # 设计模式:https://www.cnblogs.com/liuqingzheng/p/10038958.html import sys # print(sys.path) # 初始化出池对象 # 这个池应该做成单例,整个程序中只有这一个对象 # 以模块导入,天然单例 from POOL import CONN_POOL # 绝对导入(如果以相对导入,右键不能运行,因为scripts已经在环境变量,所以直接导) # pool = redis.ConnectionPool(host='127.0.0.1',port=6379, max_connections=100) # 池的大小 # 从连接池取一个链接 conn = redis.Redis(connection_pool=CONN_POOL) print(conn.get('age')) conn.close() # 把链接放回到连接池
3.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 # 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') # 7 setrange(name, offset, value) # conn.setrange('name',1,'lqz') # 8 setbit(name, offset, value) 不需要,比特位 # res=conn.getbit('name',1) # conn.setbit('name',1,0) # 9 getbit(name, offset) # 10 bitcount(key, start=None, end=None) # 12 strlen(name) 字节长度 # res=conn.strlen('name') # 13 incr(self, name, amount=1) 自增,统计网站,文章,课程访问量 # conn.incr('age') # 14 incrbyfloat(self, name, amount=1.0) # conn.incrbyfloat('age',8.9) # 15 decr(self, name, amount=1) # conn.decr('age') # 16 append(key, value) conn.append('age','nb') # print(res) conn.close() '''' get set strlen append '''
4.redis列表操作
''' 1 lpush(name,values) 2 lpushx(name,value) 3 llen(name) 4 linsert(name, where, refvalue, value)) 4 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) 12brpoplpush(src, dst, timeout=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 blpop '''
5.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) # 2 hmset(name, mapping) # conn.hmset('userinfo',{'name':'lqz','age':19}) # 3 hget(name,key) # res=conn.hget('userinfo','age') # 4 hgetall(name) # res=type(conn.hgetall('userinfo')) # res=conn.hgetall('userinfo')[b'age'] # 5 hkeys(name) # res=conn.hkeys('userinfo') # 6 hvals(name) # res=conn.hvals('userinfo') # 7 hexists(name, key) # res=conn.hexists('userinfo','age') # 8 hdel(name,*keys) # res=conn.hdel('userinfo','wife') # res=conn.hdel('wife','name','age','xx') # 9 hincrby(name, key, amount=1) # res=conn.hincrby('wife','height') # 10 hincrbyfloat(name, key, amount=1.0) # 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) # 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) # print(res) conn.close() ''' hset hget hmset hmget hexists '''
6.通用操作
''' 1 delete(*names) # 根据删除redis中的任意数据类型 2 exists(name) # 检测redis的name是否存在 3 keys(pattern='*') 4 expire(name ,time) 5 rename(src, dst) 6 move(name, db)) 7 randomkey() 8 type(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)