Redis基本用法

1 Redis介绍与安装

# redis:缓存数据库【大部分时间做缓存,但不仅仅可以做缓存】,非关系型数据库【区别于mysql关系型数据库】
	-nosql:非关系型数据库
    -c语言写的 服务(监听端口),用来存储数据的,数据是存储在内存中,取值,放值的速度非常快,10w qps
# 面试题:redis为什么这么快
	-1 纯内存操作
    -2 往来模型使用的IO多路复用(epoll)(可以处理的请求数更多)
    -3 6.x之前,单进程,单线程架构,没用线程进程间切换,更少的消耗资源
    
# key-value形式存储,没有表的概念

# 版本
	最新: 7.x
    公司里 5.x比较多
# 安装
	-mac   源码编译安装
    -linux 源码编译安装
    -win   微软自己,基于源码,改动,编译成安装包
     	# 最新5.x版本 https://github.com/tporadowski/redis/releases/
    	# 最新3.x版本 https://github.com/microsoftarchive/redis/releases
        
        一路下一步,安装完释放出两个命令,会把redis自动加入到服务中
        redis-server   #  mysqld  服务端的启动命令
        redis-cli      # mysql    客户端的启动命令
# 安装目录
	redis-server  
    redis-cli
    redis.windows-service.conf   配置文件
    	-bind 127.0.0.1   # 服务,跑在的地址
        -port 6379        #监听的端口
        
        
        
# 启动redis
	1 方式一:
    	-在服务中,点击启动,后台启动
    2 方式二:使用命令
    	redis-server 指定配置文件  如果不指定,会默认
        
# 客户端连接redis
	1 方式一
		redis-cli   #默认连接本地的6379端口
    2 方式二:
    	redis-cli -h 地址 -p 端口
        
        
    3 使用图形化客户端操作
    	-Redis Desktop Manager :开源的,原来免费,后来收费了  推荐用(mac,win,linux 都有)
        	-Qt5  qt是个平台,专门用来做图形化界面的 
            -可以使用c++写
            -可以使用python写  pyqt5  使用python写图形化界面 (少量公司再用)
            -resp-2022.1.0.0.exe 一路下一步,安装完启动起来
        -Redis Client  小众
        
    	图形化界面,连接redis 输入地址和端口,点击连接即可
# redis默认有16个库,默认连进去就是第0个
         

2 Redis普通连接和连接池

# python  相当于客户端,操作redis
# 安装模块:pip install redis


#补充: django 中操作mysql,没有连接池的,一个请求就是一个mysql连接
	-可能会有问题,并发数过高,导致mysql连接数过高,影响mysql性能
    -使用django连接池:https://blog.51cto.com/liangdongchang/5140039
    

2.1 普通连接

# 安装redis 模块:pip install redis

# 1 导入模块的Redis类
from redis import Redis

# 2 实例化得到对象
conn = Redis(host='127.0.0.1', port=6379)

# 3 使用conn,操作redis
# 获取name的值
# res = conn.get('name')  # 返回数据是bytes格式

# 4 设置值
conn.set('age', 19)

conn.close()

2.2 连接池连接

###pool.py
import redis
POOL = redis.ConnectionPool(max_connections=10, host='127.0.0.1', port=6379)  # 创建一个大小为10的redis连接池

### 测试代码
import redis
from threading import Thread
from pool import POOL
def task():
    # 做成模块后,导入,无论导入多少次,导入的都是那一个POOL对象
    conn = redis.Redis(connection_pool=POOL)  # 报错的原因是拿连接,池里不够了,没有等待,线程报错  设置等待,参数
    print(conn.get('name'))
    
for i in range(1000):
    t = Thread(target=task)  # 每次都是一个新的连接,会导致连接数过多
    t.start()

    
# 单例模式:设计模式  23 中设计模式
	-全局只有一个 这个对象 
    p1=Person()  # p1 对象
    p2=Person()  # p2 新对象
    
    -单例模式的6种方式
    	-1 模块导入方式
        -2 。。。

3 Redis之字符串类型

# redis 是key-value形式存储
# redis 数据放在内存中,如果断电,数据丢失---》需要有持久化的方案
# 自带一个持久化放完,正常退出 数据会写入硬盘,下次进入会自动取出

# 5 种数据类型,value的类型
	-字符串:用的最多,做缓存,做计数器
    -列表:简单的消息队列
    -字典(hash):缓存
    -集合:去重
    -有序集合:排行榜
# 字符串类型的使用
'''
1 set(name, value, ex=None, px=None, nx=False, xx=False)
2 setnx(name, value)
3 setex(name, value, time)
4 psetex(name, time_ms, value)
5 mset(*args, **kwargs)
6 get(name)
7 mget(keys, *args)
8 getset(name, value)
9 getrange(key, start, end)
10 setrange(name, offset, value)
11 setbit(name, offset, value)
12 getbit(name, offset)
13 bitcount(key, start=None, end=None)
14 bitop(operation, dest, *keys)
15 strlen(name)
16 incr(self, name, amount=1)
# incrby
17 incrbyfloat(self, name, amount=1.0)
18 decr(self, name, amount=1)
19 append(key, value)
'''
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('hobby','篮球',ex=3)
conn.set('hobby','篮球',px=3)
conn.set('name','guts',nx=True)
conn.set('name','guts',nx=False)
conn.set('hobby','篮球',xx=True)
conn.set('hobby','篮球',xx=False)
# redis--->实现分步式锁,底层基于nx实现的

# 2 setnx(name,value)
# 等同于:conn.set('name', 'lqz',nx=True)
conn.setnx('name', '刘亦菲')

# 3 setex(name, value, time)
# 等同于:conn.set('name','lqz',ex=3)
conn.setex('wife', 3, '刘亦菲')

# 4 psetex(name, time_ms, value)
conn.psetex('wife', 3000, '刘亦菲')

# 5 mset(*args, **kwargs)
conn.mset({'wife': '刘亦菲', 'hobby': '篮球'})

# 6 get(name)
print(str(conn.get('wife'), encoding='utf-8'))
print(conn.get('wife'))

# 7 mget(key, *args)
res = conn.mget('wife', 'hobby')
res = conn.mget(['wife', 'hobby'])
print(res)

# 8 getset(name, value)
res = str(conn.getset('wife', '迪丽热巴'), encoding='utf-8')
res = conn.getset('wife', '迪丽热巴')
print(res)

# 9 getrange(key, start, end)
res = str(conn.getrange('wife', 0, 2), encoding='utf-8')  # 字节长度,不是字符长度,前闭后闭区间
print(res)

# 10 setrange(name, offset, value)
conn.setrange('wife', 2, 'bbb')

# -------比特位------操作
# 11 setbit(name, offset, value)
# 12 getbit(name, offset)
# 13 bitcount(key, strat=None, end=None)
# -------比特位------操作

# 14 bitop(operation, dest, *keys)  获取多个值,并将值做位运算,将最后的结构保存至新的name对应的值

# 15 strlen(name)
res = conn.strlen('hobby')  # 统计字节长度
print(res)

# 16 incr(self, name, amount=1)
# 自增,不会出并发安全问题,单线程架构,并发量高
conn.incr('age') 每次都是默认自增1
incrby # 其中key就是redis中的键,将key所存储的值加上增量interger。如果key不存在,那么key的值就会被初始化为0,然后再执行incrby命令

# 17 incrbyfloat(self, name, amount=1.0)
conn.incrbyfloat('age', 1.2)

# 18 decr(self, name, amount=1)  # 自减
conn.decrby('age')
conn.decrby('age', -1)

# 19 append(key, value)
# conn.append('hobby', 'sb')

print(conn.strlen('hobby'))

conn.close()

'''
需要记住的
set
get
strlen  字节长度
incr
'''

4 redis之列表

'''
1 lpush(name, values)
2 rpush(name, values) 表示从右向左操作
3 lpushx(name, value)
4 rpushx(name, value) 表示从右向左操作
5 llen(name)
6 linsert(name, where, refvalue, value)
7 r.lset(name, index, value)
8 r.lrem(name, value, num)
9 lpop(name)
10 rpop(name)
11 lindex(name, index)
12 lrange(name, start, end)
13 ltrim(name, start, end)
14 rpoplpush(scr, dst)
15 blpop(keys, timeout)
16 r.brpop(keys, timeout)
17 brpoplpush(scr, dst, timeout=0)
'''

import redis

conn = redis.Redis()
# 1 lpush(name, values)  从左侧插入 创建列表
# conn.lpush('girls', '刘亦菲', '迪丽热巴')
# conn.lpush('girls', '深田咏美')

# 2 rpush(name, values) 表示从右向左操作
# conn.rpush('girls', '小红')

# 3 lpushx(name, value)  键存在 从左侧插入 键不存在不操作
# conn.lpushx('boys','小刚')
# conn.lpush('boys','小刚')
# conn.lpushx('girls','小刚')

# 4 rpushx(name, value) 键存在 从右侧插入 键不存在不操作
# conn.rpushx('girls', '古力娜扎')

# 5 llen(name)  列表中值的个数
# res = conn.llen('girls')
# print(res)

# 6 linsert(name, where, refvalue, value))
# 键 前或后 目标值 插入值
# conn.linsert('girls','before','迪丽热巴','古力娜扎')
# conn.linsert('girls', 'after', '小红', '小绿')
# conn.linsert('girls', 'after', '小黑', '小嘿嘿')  # 没有标杆,插入不进去

# 7 r.lset(name, index, value)  # 按索引位置改值 索引从0开始
# conn.lset('girls', 1, 'xxx') 

# 8 r.lrem(name, num, value)
# conn.lrem('girls',1,'xxx')  # 从左侧开始,删除1个
# conn.lrem('girls',-1,'xxx')  # 从右侧开始,删除1个
# conn.lrem('girls',0,'xxx')  # 从左开始,全删除

# 9 lpop(name) 从左侧弹出一个值
# res=conn.lpop('girls')
# print(res)

# 10 rpop(name) 从右侧弹出一个值

# 11 lindex(name, index)  按索引取值
# res = str(conn.lindex('girls', 1), encoding='utf-8')
# print(res)

# 12 lrange(name, start, end)
# res = conn.lrange('girls', 0, 2)  前闭后闭区间 取出来的是个列表
# for i in res:
#     print(str(i, encoding='utf-8'))

# 13 ltrim(name, start, end)  移除这个区间之外的值
# conn.ltrim('girls',2,3)

# 14 rpoplpush(src, dst)  从第一个列表的右边弹出拿到第二个列表的左边

# 15 blpop(keys, timeout)  # 记住 ,可以做消息队列使用  阻塞式弹出,如果没有,就阻塞
# res=conn.blpop('boys')
# print(res)

# 16 r.brpop(keys, timeout),从右向左获取数据 阻塞式弹出

# 17 brpoplpush(src, dst, timeout=0) 从第一个列表的右边弹出拿到第二个列表的左边  阻塞式弹出

conn.close()


'''
lpush
lpop
llen
lrange
'''

5 redis之hash

'''
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) 键  值是hash(字典) k:v
# conn.hset('userinfo','name','lqz')
# conn.hset('userinfo',mapping={'age':19,'hobby':'篮球'})

# 2 hmset(name, mapping)   # 批量设置,被弃用了,以后都使用hset
# conn.hmset('userinfo2',{'age':19,'hobby':'篮球'})

# 3 hget(name,key)  按键 hash的k取值
# res=conn.hget('userinfo','name')
# print(res)

# 4 hmget(name, keys, *args)  取值 放在列表中
# res=conn.hmget('userinfo',['name','age'])
# res = conn.hmget('userinfo', 'name', 'age')
# print(res)

# 5 hgetall(name)  # 慎用 一次全部取出
# res=conn.hgetall('userinfo')
# print(res)

# 6 hlen(name)  hash个数
# res=conn.hlen('userinfo')
# print(res)

# 7 hkeys(name)  查看 hash的k
# res=conn.hkeys('userinfo')
# print(res)

# 8 hvals(name)  查看 hash的v
# res=conn.hvals('userinfo')
# print(res)

# 9 hexists(name, key) 判断是否有hash 返回布尔值
# res = conn.hexists('userinfo', 'name')
# res = conn.hexists('userinfo', 'name1')
# print(res)

# 10 hdel(name,*keys)  按k删除键值对
# res = conn.hdel('userinfo', 'age')
# print(res)

# 11 hincrby(name, key, amount=1)  自增 amount自增数
conn.hincrby('userinfo', 'age', 2)
# article_count ={
#     '1001':0,
#     '1002':2,
#     '3009':9
# }

# 12 hincrbyfloat(name, key, amount=1.0)  自增 浮点型
# res = conn.hincrbyfloat('userinfo', 'age', amount=1.0)
# print(res)

# hgetall  会一次性全取出,效率低,可以能占内存很多
# 分批获取,hash类型是无序
# 插入一批数据
# for i in range(1000):
#     conn.hset('hash_test','id_%s'%i,'鸡蛋_%s号'%i)

# res=conn.hgetall('hash_test')   # 可以,但是不好,一次性拿出,可能占很大内存
# print(res)
# 13 hscan(name, cursor=0, match=None, count=None)   # 它不单独使用,拿的数据,不是特别准备
# res = conn.hscan('hash_test', cursor=0, count=5)
# print(len(res[1])) #(数字,拿出来的10条数据)   数字是下一个游标位置



# 咱们用这个,它内部用了hscan,等同于hgetall 所有数据都拿出来,count的作用是,生成器,每次拿count个个数
# 14 hscan_iter(name, match=None, count=None)
res=conn.hscan_iter('hash_test',count=10)
# print(res)  # generator 只要函数中有yield关键字,这个函数执行的结果就是生成器 ,生成器就是迭代器,可以被for循环
# for i in res:
#     print(i)

conn.close()

'''
hset
hget
hmget
hlen
hdel
hscan_iter  获取所有值,但是省内存 等同于hgetall
'''

6 redis其他操作

''' 通用操作,不指定类型,所有类型都支持
1 delete(*names)
2 exists(name)
3 keys(pattern='*')
4 expire(name ,time)
5 rename(src, dst)
6 move(name, db))
7 randomkey()
8 type(name)
'''

import redis

conn = redis.Redis()

# 1 delete(*names)
# conn.delete('name', 'userinfo2')
# conn.delete(['name', 'userinfo2'])  # 不能用它
# conn.delete(*['name', 'userinfo2'])  # 可以用它

# 2 exists(name) 判断键是否存在, 返回0/1
# res=conn.exists('userinfo')
# print(res)

# 3 keys(pattern='*')  匹配取值
# res=conn.keys('w?e')  #  ?表示一个字符,   * 表示多个字符
# print(res)

# 4 expire(name ,time)  设置过期时间
# conn.expire('userinfo',3)

# 5 rename(src, dst)  改名
# conn.rename('hobby','hobby111')

# 6 move(name, db))  移动库
# conn.move('hobby111',8)

# 7 randomkey()  随机获取一个key
# res=conn.randomkey()
# print(res)

# 8 type(name)  查看数据类型
# print(conn.type('girls'))
print(conn.type('age'))
conn.close()

7 redis 管道

# 事务---》四大特性:
	-原子性
    -一致性
    -隔离性
    -持久性
    
# redis支持事务吗   单实例才支持所谓的事务,支持事务是基于管道的
	-执行命令  一条一条执行
    	-张三  金额 -100   conn.decr('zhangsan_je', 100)
        电脑寄了
        -你  金额 100   conn.incr('lisi_je', 100)
        
    - 把这两条命令,放到一个管道中,先不执行,先执行execute,一次都执行完成    
    conn.decr('zhangsan_je', 100)   conn.incr('lisi_je', 100)
    
# 如何使用
import redis
conn = redis.Redis()
p = conn.pipeline(transaction=True)
p.multi()
p.decr('zhangsan_je', 100)
# rasie Exception('寄了')
p.incr('lisi_je', 100)

p.execute()
conn.close()

8 django中使用redis

## 方式一:自定义包方案(通用的, 不针对框架,所有框架都可以用)
	-第一步:写一个pool.py
    import redis
    POOL = redis.ConnectionPool(max_connections=100)
    -第二步:以后在使用的地方,直接导入使用即可
    conn = redis.Redis(connection_pool=POOL)
    conn.icnr('count')
    res = conn.get('count')
    
## 方式二:django 方案,
	-方案一:django的缓存使用redis 【推荐使用】
    	-settings.py 中配置
        CACHES = {
            "default": {
                "BACKEND": "django_redis.cache.RedisCache",
                "LOCATION": "redis://127.0.0.1:6379",
                "OPTIONS": {
                    "CLIENT_CLASS": "django_reids.client.DefaultClient",
                    "CONNECTION_POOL_KWARGS": {"max_connections": 100}
                    # "PASSWORD": "123",
                }
            }
        }
        
        -在使用redis的地方:cache.set('count', res+1)
        -pickle序列化后,存入的
        
     -方案二:第三方:django-redis模块
        from django_redis import get_redis_connection
        def test_redis(request):
            conn=get_redis_connection()
            print(conn.get('count'))
            return JsonResponse({'count': '今天这个接口被访问的次数为%s'}, json_dumps_params={'ensure_ascii': False})
posted @ 2023-03-07 20:06  理塘丁真1!5!  阅读(41)  评论(0编辑  收藏  举报