Redis

一、Redis介绍

Redis是一种非关系型数据库,基于内存、key-value存储的数据库,性能非常高。

由于Redis是内存存储,数据都在内存中,所以重启就没了(没有做持久化)

性能很高,io多路复用,epoll模型,但官方不支持windows

Redis五大数据类型:
string(字符串)、list(列表)、set(集合)、hash(哈希类型)、sorted sets(有序集合)

关系型数据库:MySQL,Oracle,DB2,SQL Server 等
非关系型数据库:Redis,MongoDB 等

安装

Redis是使用c语言写的,c不能跨平台,还好有第三方已经在windows上编译好了,拿到就是可执行文件

# 下载地址(非官方)
https://github.com/tporadowski/redis/releases/
# 下载安装直接一直无脑下一步就行

# 下载之后会自动做成windows服务,自动启动服务
    
# 我们也可以使用命令手动启动
redis-server.exe
redis-server.exe  配置文件路径
        
# 客户端连接
redis-cli
redis-cli -h 127.0.0.1 -p 6379

二、Redis连接和连接池连接

# redis模块安装
pip install redis

##############################################################

# 普通连接
import redis

# 拿到一个连接,通过连接操作数据
conn = redis.Redis(host='localhost', port=6379)
conn.set('name', 'poco')
conn.close()

##############################################################

# 连接池连接
import redis

# 创建池,池的大小是10,最多放10个连接
POOL = redis.ConnectionPool(max_connections=10)
# 从池中获取连接
conn = redis.Redis(connection_pool=POOL)
conn.set('age', 19)
conn.close()

'''
如果POOL = redis...这行创建池的代码被反复执行(放在线程里写),就会创建N多个池,为了避免这种情况,需要做成单例()
'''

三、Redis操作

1、字符串操作

import redis
conn = redis.Redis()

'''
ex,过期时间(秒)
px,过期时间(毫秒)
nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
'''
conn.set('hobby', '篮球', ex=5)  # 五秒后数据就没了
conn.set('age', 18, nx=True)  # 如果有age存在, 操作不执行

# 设置值,只有name不存在时,执行设置操作(添加),如果存在,不会修改
conn.setnx('name', 'poco')  # 和nx效果一样

# 批量存入值
conn.mset({'name1':'lyf','name2':'ycy'})

# get获取值,mget批量获取值
print(conn.get('name1'))
print(conn.mget('name1', 'name2'))

# get和set结合,获取值并修改值
print(conn.getset('name1','glnz'))

# 取出0到2索引对应的字节
print(conn.getrange('name1', 0, 2))
# 修改name1索引3之后的值为EEEEE
conn.setrange('name1', 3, 'EEEEE')

# 获取name1的字节数
print(conn.strlen('name1'))

# 执行一次自增+1
conn.incr('age')
# 自减
conn.decr('age')
# 浮点型自增,自增1.5
conn.incrbyfloat('age', 1.5)

conn.close()

2、哈希操作

import redis
conn = redis.Redis()

# 哈希的set,存值
conn.hset('hash1', 'name', 'poco')
conn.hset('hash1', 'age', '18')

# 哈希的get,取值
print(conn.hget('hash1','age'))

# 批量存值
conn.hmset('hash1', mapping={'name': 'poco', 'age': 22})

# 批量取值
print(conn.hmget('hash1', ['name', 'age']))

# 获取所有值(生产环境中慎用)
print(conn.hgetall('hash1'))

# 获取所有key值
print(conn.hkeys('hash1'))

# 获取所有value值
print(conn.hvals('hash1'))

# 检查hash1里age这个key值是否存在
print(conn.hexists('hash1', 'age'))

# 分批获取
for item in conn.hscan_iter('hash1'):
    print(item)

conn.close()

3、列表操作

import redis
conn = redis.Redis()

# 列表的存值,班级是name,后面的是列表的元素
conn.lpush('班级', '1班', '2班', '3班')

# name存在时才可以添加值
conn.lpushx('班级', '4班')

# 获取name对应的list元素的个数
print(conn.llen('班级'))

# 在name对应的列表的某个元素的前或者后插入一个新值(before表示前,after表示后)
conn.linsert('班级', 'after', '3班', '3.5班')

# 为name对应的list中的某一个索引位置重新赋值
conn.lset('班级', 1, '加强班')

# 在name对应的list中删除指定的值
conn.lrem('班级', 0, '加强班')  # 移除所有的'加强班'
conn.lrem('班级', 1, '加强班')  # 从左往右移除一个'加强班'
conn.lrem('班级', -2, '加强班')  # 从右往左移除两个'加强班'

# 删除name对应的list中最左侧的元素,并且返回这个值
res = conn.lpop('班级')
res2 = conn.rpop('班级')  # 删除最右侧

# 获取name列表中的某个索引对应的元素
print(conn.lindex('班级', 1))

# 获取name列表中0到3索引的元素(包括0和3)
print(conn.lrange('班级', 0, 3))

# 只保留索引1到3的元素(包括1和3)
conn.ltrim('班级', 1, 3)

# 取出name对应列表的第一个元素,如果没有值则阻塞,一直到有值为止
res = conn.blpop('班级')
print(res)

print(conn.blpop('班级', 3))  # 可以设置timeout来指定阻塞的时间

conn.close()

Redis通用操作

import redis
conn = redis.Redis()

# 直接删除redis的任意数据类型
conn.delete('info')

# 判断redis的name是否存在,返回1和0
print(conn.exists('name2'))

# 获取所有key值,可以过滤
print(conn.keys('*'))  # 获取所有key值
print(conn.keys('n*'))  # 获取n开头的所有k值
print(conn.keys(pattern='nam?'))  # ?为任意的一个字符

# 为info设置一个过期时间
conn.expire('info', 5)  # 5秒后过期

# 重命名
conn.rename('info', 'INFO')  # 把info重新命名为INFO

# 将redis的某个类型移动到指定的db下
conn.move('INFO', 5)

# 随机弹出一个name
print(conn.randomkey())

# 查看某个key的类型
print(conn.type('name'))

conn.close()

四、Redis管道

Redis是非关系型数据库,不支持事务,所以我们通过管道来模拟事务

我们模拟两个账号转账,只有两条命令同时执行,才会成功,中间但凡有一条命令没能执行,则管道的命令全都执行失败

管道:将所有的命令放在管道里统一执行

import redis
conn = redis.Redis()

# 创建管道
pipe = conn.pipeline(transaction=True)
# 开启事务
pipe.multi()
# 向管道中放入一条命令
pipe.decrby('poco', '50')  # poco减50
# 又向管道放入一条命令
pipe.incrby('hy', '50')  # hy加50

pipe.execute()  # 让管道中的命令执行

五、Django使用Redis

通用方案

'''
建一个pool.py,写如下代码
'''
import redis
POOL = redis.ConnectionPool(max_connections=1000)  # 连接池大小为1000

'''
然后在使用的位置将pool里的POOL导入过来使用
'''
from .pool import POOL

import redis
def test(request):
    conn = redis.Redis(connection_pool=POOL)
    res = conn.get('name')
    print(res)
    return HttpResponse('ok')

Django方案

# 安装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",
        }
    }
}

# 然后在使用的位置使用
from django_redis import get_redis_connection
def test(request):
    conn = get_redis_connection()  #从连接池中拿一个连接
    res=conn.get('name')  # 拿到redis的name
    print(res)
    return HttpResponse('ok')


# 一旦使用了它,后续的djagno缓存,都缓存到redis中
cache.set('name','xxx')

'''django的缓存很高级,可以缓存python中所有的数据类型,包括对象---》把对象通过pickle序列化成二进制,存到redis的字符串中'''
posted @ 2021-10-10 17:13  黑影Poco  阅读(131)  评论(0)    收藏  举报