Redis基本使用

1 redis介绍


# redis 是什么,特点,存数据的地方,cs架构,数据库,开源软件
    1 是一个软件(用c语言写的,初级版本代码只有1w多行  7.x,公司 5.x,4.x多)
    2 非关系型(mysql关系型数据库;没有外键关联关系)数据库,nosql(not only sql)数据库,
    3 数据都放在内存中(读写速度超级快--》每秒的qps 10w)
    4 key-value形式存储
    5 有5大数据类型(字符串,list,hash(字典),集合,有序集合)
    
    
# redis 好处
    (1) 速度快,因为数据存在内存中,类似于python的字典的优势就是查找和操作的速度快
    (2) 支持丰富数据类型,支持string,list,set,sorted set,hash
    (3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
    (4) 丰富的特性:可用于缓存(最广泛:缓存数据库),消息,按key设置过期时间,过期后将会自动删除
    
# redis 最适合的场景
	(1)会话缓存(Session Cache)---》原来session放在了djagno-session表中,速度慢,放到redis中速度超级快
	(2)全页缓存,接口缓存:
	(3)队列:程序的解耦,不是专业的,真正专业的消息队列:kafka,rabbitmq...
	(4)排行榜/计数器:有序集合, 字符串类型做计数器累加(由于6.x之前redis是单线程单进程架构,不存在并发安全问题)
        
        
# redis 为什么这么快?
    -1 纯内存操作
    -2 使用io多路复用的网络模型(select,poll,epoll模型),epoll模型
    -3 单线程,单进程架构,没有进程线程间切换的消耗

2 安装


# redis的安装(linux,mac,win)
    -redis作者对win的支持不好---》win不支持epoll的网络模型,只支持select
    -于是:微软就自己把redis改了改--》编译成可执行文件--》可以运行在win上
    	-两个大的分支
            -一个分支只维护到3.x
            	-https://github.com/microsoftarchive/redis/releases
            -另一个分支维护到5.x
            	-https://github.com/tporadowski/redis/releases/
	-下载完成,一路下一步
    -会创建出一个redis服务---(mysql服务),安装路径加入到环境变量了
    -以后,启动服务,在任意路径敲 redis-cli 都能识别
    
    -启动redis服务(redis的服务的,执行命令)
    	redis-server.exe redis.windows-service.conf
    -客户端连接(cmd窗口下)
    	redis-cli -h 127.0.0.1 -p 6379
        redis-cli 
     -redis 是key-value存储,但是它默认有16个库
# 图形化客户端--》选择很多
    -redis-desktop-manage  源码是个开源软件,用qt写的,图形化界面,开始免费,后来用的人多了,收费了,99永久----》等同于navicate
    -一路下一步

3 redis基本链接和连接池

# python 写脚本,操作redis,本质python代码就是redis的客户端

# pip install redis

3.1 普通链接

# 第一步:导入Redis类
from redis import Redis

# 第二部: 实例化得到对象
conn=Redis(host="localhost",port=6379,)  # 默认连本地
# 第三步:操作数据(非常对方法,操作:字符串,hash,链表操作)
conn.set('name','lqz')
conn.close()

3.2 连接池

pool.py

import redis
POOL = redis.ConnectionPool(max_connections=10)

链接

from pool import POOL  # 使用模块导入,相当于使用天然的单例模式,只创建一次连接池

# 第三步:从池中取一个链接使用
conn = redis.Redis(connection_pool=POOL)
# 第四步:操作数据(非常对方法,操作:字符串,hash,链表操作)
conn.set('age', '19')
conn.close()

image-20220713120528675

4 redis字符串操作

# redis:5大数据类型---》字符串,链表,hash,集合,有序集合
# redis支持5大数据类型,只支持到一层,第二层必须是字符串
# Memcached:只支持字符串,都是纯内存,断电数据丢失      redis可以持久化

'''
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)
'''

from redis import Redis

conn = Redis()

### 代码验证

1 set(name, value, ex=None, px=None, nx=False, xx=False)  # 设置值
    conn.set('name','pyy')
# ex:过期时间(秒),px,过期时间(毫秒)
    conn.set('age',19,ex=5)  # 过期就没有了---》最适合存 验证码
# nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
    conn.set('name','lyf',nx=True)
    conn.set('name','lyf')
# xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
    conn.set('name','lqz',xx=True)


2 setnx(name, value)--->等同于set  nx=True  # key不存在才执行set
    conn.setnx('name','xxx')

3 psetex(name, time_ms, value)   # 插值,并以毫秒计时
    conn.psetex('age',3000,'19')


4 mset(*args, **kwargs)  # 批量设置值
    conn.mset({'age': 19, 'name': 'lxx', 'wife': '刘亦菲'})

# 面试:一次mset和多次set的区别?

4 get(name)  # 获取值
    res=conn.get('wife')
    print(str(res,encoding='utf-8'))
    s='李清照'
    print(bytes(s,encoding='utf-8'))



5 mget(keys, *args)  # 批量获取值
    res=conn.mget('name','age','wife')
    res=conn.mget(['name','age','wife'])
    print(res)


6 getset(name, value)  # 获取原来的值并设置新的值
    res=conn.getset('name','彭于晏')
    print(res)


7 getrange(key, start, end)  # 根据起始和终止,获取字符串,以字节计数  ,中在redis中存储是用utf-8存储的
    res=conn.getrange('name',0,2)
    print(str(res,encoding='utf-8'))


8 setrange(name, offset, value)  # 指定位置设置值
    conn.setrange('name',3,'bbb')

9 setbit(name, offset, value)   # 指定比特位修改成
    conn.setbit('name',7,0)   #  00000000   00000000   00000000


10 getbit(name, offset)  # 了解,获取指定位置的比特位值
    print(conn.getbit('name',7))

11 bitcount(key, start=None, end=None)
    print(conn.bitcount('name',0,4))

12 strlen(name)   # 返回name对应值的字节长度
    print(conn.strlen('name'))


13 incrby(self, name, amount=1)  # 计数器,不写默认+1
    conn.incrby('age')


14 incrbyfloat(self, name, amount=1.0)  # 小数整数都能加
    conn.incrbyfloat('age')


15 decrby(self, name, amount=1)  # 默认-1
    conn.decrby('age')


16 append(key, value)  # 在某数value追加值

    conn.append('name','sb')


conn.close()


5 redis hash操作

# 字典---》基于数组存储---》根据key值通过hash函数运算得到一个地址,把value值放进去
'''
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)
9hexists(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)
'''

from redis import Redis

conn = Redis()
# 1 hset(name, key, value)  # 新增hash值,name是表示key和value的hash名
    conn.hset('userinfo','name','lqz')
    conn.hset('userinfo','age','29')


# 2 hmset(name, mapping)  # 设置hash的多个值
    conn.hmset('userinfo1', {'name': 'pyy', 'age': 39})

    conn.hset('userinfo2',mapping={'name': '刘亦菲', 'age': 39})

# 3 hget(name,key)  # 获取hash的某个value值
    print(conn.hget('userinfo','age'))

# 4 hmget(name, keys, *args)  # 获取hash的多个value值
    print(conn.hmget('userinfo',['name','age']))


# 5 hgetall(name)  # 获取所有,慎用---》如果hash类型数据量特别大,很可能撑爆内存
    print(conn.hgetall('userinfo'))


# 6 hlen(name)  # 计算hash的数据个数
    print(conn.hlen('userinfo'))

# 7 hkeys(name)  # 获取hash的所有key
    print(conn.hkeys('userinfo'))

# 8 hvals(name)  # 获取hash的所有value
    print(conn.hvals('userinfo'))


# 9 hexists(name, key)  # 存在返回1,不存在返回0
    print(conn.hexists('userinfo','wife'))
    print(conn.hexists('userinfo','age'))

# 10 hdel(name,*keys)  # 删掉hash某个key-value
    conn.hdel('userinfo','age')

# 11 hincrby(name, key, amount=1)  # hash中某个值整数增加
    conn.hincrby('userinfo1','age')

# 12 hincrbyfloat(name, key, amount=1.0)  # hash中某个值整数或小数增加



# 注意一下---》不建议使用hgetall---》分批取值
# for i in range(1000):
#     conn.hset('htest','name_%s'%i,'鸡蛋_%s'%i)
# res=conn.hgetall('htest')
# print(res)

# 13 hscan(name, cursor=0, match=None, count=None)  # 查看hash的所有key-value--- >这个不是直接用,需要配合hscan_iter来用
    res=conn.hscan('htest',cursor=0,count=55)
    print(res)
    print(len(res[1]))

# 14 hscan_iter(name, match=None, count=None)

# 把htest数据全取出来打印,批量获取,每次取10条
    for item in conn.hscan_iter('htest',count=10):
        print(item)

# for item in conn.hgetall('htest'):
#     print(item)

# 15 hgetall(hsah名)  # 获取hash所有key-value
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 自定义增量迭代
'''

from redis import Redis

conn = Redis()

# 1 lpush(name,values)
	conn.lpush('girl_friend','刘亦菲','迪丽热巴')

# 2 lpushx(name,value) 只有name已经存在时,值添加到列表的最左边
	conn.lpushx('girl_friend','杨颖')

# 3 rpushx(name, value) 表示从右向左操作
	conn.rpush('girl_friend','彭于晏')

# 4 llen(name)
	print(conn.llen('girl_friend'))

# 5 linsert(name, where, refvalue, value))
# name: redis的key值, where: before或者after   refvalue: 列表中的元素(刘亦菲), value :要插入的值
	conn.linsert('girl_friend',where='after',refvalue='刘亦菲',value='lqz')
	conn.linsert('girl_friend',where='before',refvalue='刘亦菲',value='lqz')
	conn.linsert('girl_friend',where='before',refvalue='迪丽热巴',value='lqz')


# 6 lset(name, index, value)  # 从零开始
	conn.lset('girl_friend',0,'凤姐')

# 7 lrem(name, value, num)   # 正数是从左侧,负数是从右侧,0表示删所有
	conn.lrem('girl_friend',1,'lqz')  # 从左侧删1个
	conn.lrem('girl_friend',-1,'lqz')  # 从右侧删1个


# 8 lpop(name)  # 从左侧弹出
	res=conn.lpop('girl_friend')
	res = conn.rpop('girl_friend')  # 从右侧弹出


# 9 lindex(name, index)
	res=conn.lindex('girl_friend',2)  # 按照索引取值
	print(str(res,encoding='utf-8'))


# 10 lrange(name, start, end)
	res=conn.lrange('girl_friend',0,2)   # ,按范围取值,前闭后闭区间
	print(conn.lrange('test',0,conn.llen('test')))  # 取所有

# 11 ltrim(name, start, end)  # 修剪
	conn.ltrim('girl_friend',1,3)  # 只保留参数范围内的数据

# 12 rpoplpush(src, dst)  
	conn.lpush('wife1','ee')
	conn.rpoplpush('girl_friend','wife1')  # 将girlfriend列表中最右边元素弹出放到wife1列表最左边


# 13 blpop(keys, timeout)  # 记住---》消息队列本质就是基于它---》redis可以作为消息队列
# 阻塞式 弹出,如果列表中有值,就弹出,如果没有值就阻塞,直到有值再弹出
	print(conn.blpop('lqz'))

# 14 brpoplpush(src, dst, timeout=0)
	右侧弹出,左侧插入
# 15 自定义增量迭代----》

'''
# 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
    # 1、获取name对应的所有列表
    # 2、循环列表
# 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:


'''
conn.lpush('test',*[1,2,3,4,45,5,6,7,7,8,43,5,6,768,89,9,65,4,23,54,6757,8,68])

def scan_list(name, count=2):
    index = 0
    while True:
        data_list = conn.lrange(name, index, count + index - 1)
        if not data_list:
            return
        index += count
        for item in data_list:
            yield item

# print(conn.lrange('test', 0, 100))
for item in scan_list('test', 5):
    print('---')
    print(item)

conn.close()

7 redis管道

# redis不支持事务---》管道的操作---》多个命令放到一个管道中,然后一次性执行,要么都成功,要么都失败
# redis支持事务码?支持--》通过管道实现弱事务
	-事务四个特性
    -事务隔离级别
from redis import Redis

conn=Redis()

# 创建管道
pipe = conn.pipeline(transaction=True)
pipe.multi() # 接受多条命令,放到管道中

# 操作redis命令
pipe.decrby('zhangsan',50)
raise Exception('异常了')
pipe.incrby('lisi',50)

pipe.execute() # 一次性执行管道中所有命令,报错则都不执行
conn.close()

8 redis其它操作

# redis的通用操作---》跟类型无关的操作

from redis import Redis

conn = Redis()

# 1  delete(*names)
	conn.delete('wife')
# 2 exists(name)
	res = conn.exists('age')
	print(res)

# 3 keys(pattern='*')
	res=conn.keys('*')
	res=conn.keys('userinfo?')
	print(res)

# 4 dbsize
	res=conn.dbsize()
	print(res)

# 5 expire(name ,time)
	conn.expire('wife1',5)

# 6 rename(src, dst)
	conn.rename('test','test1')

# 7 move(name, db))
	conn.move('test1',3)

# 8 randomkey()
# 随机获取一个redis的name(不删除)
	print(conn.randomkey())


# 9 type(name)
	print(conn.type('girl_friend'))

conn.close()

9 django中集成redis

# 两种方案
	-1 通用方案:
    	-写一个pool包
        import redis
	POOL=redis.ConnectionPool(max_connections=1024,decode_responses=True)
    
        -在使用的位置导入
          conn = Redis(connection_pool=POOL)
          res = conn.get('name')
        
    -2  使用第三方:django-redis
    	-pip install django-redis
        
        -配置文件配置
            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",
                }
            }
        }
            
       -在使用的位置
    	conn = get_redis_connection()
        conn.set.....
 """
一旦配置文件配置 CACHES 后,django的缓存框架(默认是内存),存储的位置也是redis
以后根本不需要会redis的操作,只需要使用 
	cache.set('name',对象)
	cache.get()
强大之处在于不需要关注设置的类型,直接设置就行
把python的对象,通过pickle序列化后,以string形式存到redis中了
 """   	

posted @ 2022-07-13 20:22  马氵寿  阅读(50)  评论(0)    收藏  举报