Redis

一 Redis简介

redis可以支持五大(字符串string、链表list、字典hash、集合set、有序集合zset)数据类型,比起Memcached来说,它只能支持一种(字符串)数据类型。redis虽然是单线程,但是效率极高,并且可以将数据持久化;相反,Memcached只能将数据暂存到内存中,断电数据就会丢失!

二 Redis使用

2.1 Redis安装

下载Redis-x64-3.2.100.msi,在pycharm中安装redis模块

  • 使用命令行输入命令:pip3 install redis
  • 也可用pycharm
    1. settings,选择project下的Project Interpreter进行安装
    2. Terminal界面安装,输入命令:pip3 install redis

2.2 Redis连接

import redis

conn = redis.Redis('127.0.0.1', 6379)
conn.set('f1', 'hello')
print(conn.get('f1'))

# b'hello'

注意点:redis默认的是bytes的数据类型,可以加参数设置为字符串类型,decode_responses=True

import redis

conn = redis.Redis('127.0.0.1', 6379, decode_responses=True)
conn.set('f1', 'hello')
print(conn.get('f1'))   # hello

2.3 使用密码认证登陆

1. 修改配置文件

安装目录下的 C:Program Files (x86)Redisredis.windows-service.conf 文件,找到文件中的这一行:# requirepass foobared,去掉注释,将后面的foobared改为自己需要的密码即可!如:

2. 重启Redis

方法有很多,自己都可以尝试

3. 使用密码登陆

如果不使用密码登陆则无法操作Redis,会报一个NOAUTH的错,如:

所以登陆时要制定密码,-a 制定自己设置好的密码,如:redis-cli -h 127.0.0.1 -p 6379 -a test

2.4 Redis连接池

redis使用ConnectionPool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认每个Redis实例都会维护一个自己的连接池。为避免重复开启连接池,可以用单例的思想实现多个Redis实例共享一个连接池

import redis
# 实例化
POOL = redis.ConnectionPool()
conn = redis.Redis(host='127.0.0.1', port=6379, connection_pool=POOL)
conn.set('m', 'name')

print(conn.get('m'))

方法一:利用python的便利之处,导入模块来实现连接池的单例化

import redis

POOL = redis.ConnectionPool(host='127.0.0.1', port=6379)
redis_test.py
import redis
import redis_test

conn = redis.Redis(connection_pool=redis_test.POOL)
conn.set('m', 'name')
print(conn.get('m'))

方法二:安装django-redis模块,然后配置、导入,实现连接池的单例化

  • 在settings.py 文件中进行如下的配置:
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 setname(request):
     connect = get_redis_connection()
     connect.set('name', 'bob')
     return HttpResponse('success')


def getname(request):
    connect = get_redis_connection()
    name = connect.get('name')
    return HttpResponse(name)

三 Redis数据类型之string

redis中的String在内存中按照一个name对应一个value的形式来存储,如下

import redis
import redis_test

conn = redis.Redis(connection_pool=redis_test.POOL)

# set 设置值
conn.set('name', 'value', ex=None, px=None, nx=False, xx=False)
'''
    ex:过期时间(s)
    px:过期时间(ms)
    nx:设置为True,只有name不存在时,set操作才执行,值存在,不修改原值
    xx:设置为True,只有name存在时,set操作才执行,值不存在,不设置新值
'''

# get 取值
conn.get('name')

# mset 批量设置值,键值对的关系
conn.mset({'key1': 'value1', 'key2': 'value2'})

# mget 批量取值
conn.mget('key1', 'key2')
conn.mget(['key1', 'key2'])
conn.mget(('key1', 'key2'))

# strlen 返回name对应值的字节长度(一个汉字3个字节)
conn.strlen(name='key2')

# append 在key对应的值后面追加内容
conn.append(key='key1', value='value')

# incr 自增name对应的值,当name不存在时,则创建name=amount,否则,则自增
conn.incr(name='key1', amount=1)
'''
name: Redis的name
amount: 自增数(必须是整数)
'''

# decr 自减name对应的值,当name不存在时,则创建name=amount,否则,则自减
conn.decr(name='key1', amount=1)
'''
name: Redis的name
amount: 自减数(必须是整数)
'''

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

# setex 设置值,time,过期时间(数字秒 或 timedelta对象)
conn.setex(name='name', time=5, value='value')

# psetex 设置值,time_ms,过期时间(数字毫秒 或 timedelta对象)
conn.psetex(name='name', time_ms=3, value='value')

# getset 设置新值并获取原来的值
conn.getset('name', 'value')

# getrange 获取子序列(根据字节获取,非字符)
conn.getrange('key1', start=0, end=4)
'''
start: 起始位置(字节)
end: 结束位置(字节)
如: "jack" ,0-4表示 "jack"
'''

# setrange 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
conn.setrange(name='key', offset=1, value='value')
'''
offset: 字符串的索引,字节(一个汉字三个字节)
value: 要设置的值
'''
string常用操作

四 Redis数据类型之list

redis中的List在内存中按照name对应一个List的形式来存储,如下

import redis
import redis_test

# from django_redis import get_redis_connection

# conn = get_redis_connection(alias='default')

conn = redis.Redis(connection_pool=redis_test.POOL)

# lpush 设置值,存入redis的顺序是倒序,取值时按照倒序存入的顺序,如下:
conn.lpush('ll', 'bob', 'jack', 'lee')  # ll = ['lee', 'jack', 'bob']
print(conn.lindex('ll', 2))  # b'bob'

# lpushx 添加值,name存在时,会将新值添加到链表的左边
conn.lpushx(name='ll', value='zero')  # ll = ['zero', 'lee', 'jack', 'bob']
# name不存在时,不会新增数据,取值时会取到None
conn.lpushx(name='lll', value='zero')
print(conn.lindex('lll', 2))  # None

# rpush 设置值,正常顺序存取
conn.rpush('age', 12, 15, 23, 34)  # ll = [12, 15, 23, 34]
print(conn.lindex('age', 3))  # b'34'

# lpushx 添加值,name存在时,会新增数据
conn.rpushx(name='age', value=55)  # ll = [12, 15, 23, 34, 55]
# name不存在时,不会新增数据,取值时会取到None
conn.rpushx(name='ages', value=66)
print(conn.lindex('ages', 2))  # None

# llen 统计链表的长度
print(conn.llen('age'))

# linsert 插入值
conn.linsert(name='age', where='after', refvalue=23, value=111)
# ll = [12, 15, 23, 111, 34, 55]
'''
name: redis的name
where: BEFORE或AFTER(小写也可以)
refvalue: 标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
value: 要插入的新值
'''

# lset 修改值, name、index存在时,修改原值;name或index不存在时,报错
conn.lset(name='age', index=2, value=333)

# lpop 删除数据,name存在,从左边删除一个值并返回已删除的值;name不存在,返回None
print(conn.lpop(name='age'))  # b'12'

# lrem 删除值,返回删除的数据个数, name不存在时,返回0
print(conn.lrem(name='ll', count=2, value='jack'))  # 1
'''
name: redis的name
count=0,删除列表中所有的指定值;
count=n,从前到后删除n个,值不足n个时,有多少删除多少,并返回删除的个数
count=-n,从后向前删除n个,值不足n个时,有多少删除多少,并返回删除的个数
value: 要删除的值
'''

# lrange 分片取值,前闭后闭区间
print(conn.lrange(name='age', start=1, end=3))  # [b'111', b'333', b'55']
print(conn.lrange('age', 0, conn.llen('age')))  # [b'23', b'111', b'333', b'55']
'''
name: redis的name
start: 索引的起始位置
end: 索引结束位置 
'''

# ltrim 移除值,在name对应的列表中移除没有在start-end索引之间的值
conn.ltrim(name='ll', start=1, end=3)
'''
name: redis的name
start: 索引的起始位置
end: 索引结束位置(大于列表长度,则代表不移除任何)
'''

# rpoplpush 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
print(conn.rpoplpush(src='ll', dst='age'))
'''
src: 要取数据的列表的name
dst: 要添加数据的列表的name
'''

# blpop 将多个列表排列,按照从左到右的顺序去pop掉对应列表的元素
# brpop 从右向左获取数据
# 如果列表中没有值,会一直hang住,可实现简单的分布式
print(conn.blpop(keys='age', timeout=3))
'''
keys: redis的name的集合
timeout: 超时时间,当所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞
'''
# 爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值,但是只能一台机器运行取值,可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式
list常用操作
  • 自定义增量迭代
# 自定义增量迭代
conn.lpush('test', *[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 43, 45, 56, 68, 89, 99, 65, 94, 23, 54, 57, 88, 68])


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


print(conn.lrange('test', 0, 100))
# [b'68', b'88', b'57', b'54', b'23', b'94', b'65', b'99', b'89', b'68', b'56', b'45', b'43', b'9', b'8', b'7', b'6', b'5', b'5', b'4', b'3', b'2', b'1']
for i in list_iter('test'):
    print('---------------')
    print(i)

五 Redis数据类型之hash

redis中的Hash在内存中的存储格式,如下

import redis
import redis_test

conn = redis.Redis(connection_pool=redis_test.POOL)

# hset 设置值
# name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
conn.hset('mm', 'name', 'bob')
# hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)

# hget 取值
conn.hget('mm', 'key')

# hmset 批量设置值,键值对的关系
conn.hmset('mm', {'name': 'bob', 'age': 18})

# hmget 批量取值
conn.hmget('mm', 'key1', 'key2')
conn.hmget('mm', ['key1', 'key2'])
conn.hmget('mm', ('key1', 'key2'))

# hlen 返回name对应的键值对的个数
conn.hlen(name='mm')

# hkeys 获取name对应的hash中所有的key的值
conn.hkeys(name='mm')

# hvals 获取name对应的hash中所有的value的值
conn.hvals(name='mm')

# hexists 检查name对应的hash是否存在当前传入的key
conn.hexists(name='mm', key='name')

# hdel 将name对应的hash中指定key的键值对删除
conn.hdel('mm', 'name')

# hgetall 获取name对应hash的所有键值,拿到的是字典类型
conn.hgetall(name='mm')

# hincrby 自增name对应的hash中的指定key的值,不存在则创建key=amount
conn.hincrby(name='mm', key='age', amount=1)
'''
name,redis中的name
key, hash对应的key
'''

# hscan 增量式迭代取值,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,而使内存爆满
conn.hscan(name='mm', cursor=0, match=None,count=None)
'''
cursor: 游标(基于游标分批取获取数据)
match: 匹配指定key,默认None 表示所有的key
count: 每次分片后最少取值的个数,默认None
'''

# hscan_iter 利用yield封装hscan创建生成器,实现分批去redis中获取数据
conn.hscan_iter(name='mm', match=None, count=None)
'''
match: 匹配指定key,默认None 表示所有的key
count: 每次分片最少获取个数,默认None表示采用Redis的默认分片个数
'''
hash常用操作
原文地址:https://www.cnblogs.com/rongge95500/p/10191421.html