Hello Redis

Redis是啥

它是当下最受欢迎的NoSQL数据库之一,它是一个内存数据库(缓存数据库),非关系型的,对于数据的读写速度快。

Redis的优势

(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

和Memcached比较

Memcached只支持一种数据类型字符串

Memcached不支持持久化(不支持存到硬盘)

单线程、单进程,不存在并发访问的问题(新版本开始有并发访问了)

单线程为什么这么快

  • 数据在内存中
  • 运用了io多路复用技术
  • 没有进程线程间的切换

redis适合的场景

1 排行榜
2 网站访问量,文章访问量
3 缓存数据库(用的最多,就是做缓存)
4 发布订阅
5 去重
6 分布式(blpop)

Python操作redis普通连接

from redis import Redis
conn = Redis(host='127.0.0.1', port=6379)
conn.set('name', 'ggb')
print(conn.get('name'))

Python操作redis之连接池

# 将池建成单例模式(使用导模块的方式)
redis_pool.py
import redis
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379)

from redis_pool import POOL
from redis import Redis
# decode_responses默认为False,默认返回bytes类型
conn = Redis(connection_pool=POOL, decode_responses=True)
conn.set('age', '18')
print(conn.get('age'))

redis中的数据类型

字符串(string)

  • set(name, value, ex=None, px=None, nx=False, xx=False)

    在Redis中设置值,默认,不存在则创建,存在则修改
    参数:
         ex,过期时间(秒)
         px,过期时间(毫秒)
         nx,如果设置为True,则只有name不存在时,当前set操作才执行,值存在,就修改不了,执行没效果
         xx,如果设置为True,则只有name存在时,当前set操作才执行,值存在才能修改,值不存在,不会设置新值
    
  • setnx(name, value)

    设置值,只有name不存在时,执行设置操作(添加),如果存在,不会修改
    
  • setex(name, value, time)

    # 设置值
    # 参数:
        # time,过期时间(数字秒 或 timedelta对象)
    
  • psetex(name, time_ms, value)

    # 设置值
    # 参数:
        # time_ms,过期时间(数字毫秒 或 timedelta对象
    
  • mset(*args, **kwargs)

    批量设置值
        mset(k1='v1', k2='v2')
        mset({'k1': 'v1', 'k2': 'v2'})
    
  • get(name)

    获取值
    
  • mget(keys, *args)

    批量获取
        mget('k1', 'k2')
        mget(['k3', 'k4'])
    
  • getset(name, value)

    设置新值并获取原来的值
    
  • getrange(key, start, end)

    # 获取子序列(根据字节获取,非字符)
    # 参数:
        # name,Redis 的 name
        # start,起始位置(字节)
        # end,结束位置(字节)
    
  • setrange(name, offset, value)

    # 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
    # 参数:
        # offset,字符串的索引,字节(一个汉字三个字节)
        # value,要设置的值
    
  • setbit(name, offset, value)

    # 对name对应值的二进制表示的位进行操作
     
    # 参数:
        # name,redis的name
        # offset,位的索引(将值变换成二进制后再进行索引)
        # value,值只能是 1 或 0
     
    # 注:如果在Redis中有一个对应: n1 = "foo",
            那么字符串foo的二进制表示为:01100110 01101111 01101111
        所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1,
            那么最终二进制则变成 01100111 01101111 01101111,即:"goo"
    
  • getbit(name, offset)

    # 获取name对应的值的二进制表示中的某位的值 (0或1)
    
  • bitcount(key, start=None, end=None)

    # 获取name对应的值的二进制表示中 1 的个数
    # 参数:
        # key,Redis的name
        # start,位起始位置
        # end,位结束位置
    
  • bitop(operation, dest, *keys)

    # 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
    # 参数:
        # operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或)
        # dest, 新的Redis的name
        # *keys,要查找的Redis的name
    # 如:
        bitop("AND", 'new_name', 'n1', 'n2', 'n3')
        # 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中
    
  • strlen(name)

    # 返回name对应值的字节长度(一个汉字3个字节)
    
  • incr(self, name, amount=1)

    # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
    # 参数:
        # name,Redis的name
        # amount,自增数(必须是整数,可以是负数)
    # 注:同incrby
    
  • incrbyfloat(self, name, amount=1.0)

    # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
    # 参数:
        # name,Redis的name
        # amount,自增数(浮点型)
    
  • decr(self, name, amount=1)

    # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
    # 参数:
        # name,Redis的name
        # amount,自减数(整数)
    
  • append(key, value)

    # 在redis name对应的值后面追加内容
    # 参数:
        key, redis的name
        value, 要追加的字符串
    

链表(list)

  • lpush(name,values)

    # 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
    # 如:
        # r.lpush('oo', 11,22,33)
        # 保存顺序为: 33,22,11
    # 扩展:
        # rpush(name, values) 表示从右向左操作
    
  • lpushx(name,value)

    # 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
    # 更多:
        # rpushx(name, value) 表示从右向左操作
    
  • llen(name)

    # name对应的list元素的个数
    
  • linsert(name, where, refvalue, value))

    # 在name对应的列表的某一个值前或后插入一个新值
    # 参数:
        # name,redis的name
        # where,BEFORE或AFTER(小写也可以)
        # refvalue,标杆值,即:在它前后插入数据(如果存在多个标杆值,以找到的第一个为准)
        # value,要插入的数据
    
  • lset(name, index, value)

    # 对name对应的list中的某一个索引位置重新赋值
     
    # 参数:
        # name,redis的name
        # index,list的索引位置
        # value,要设置的值
    
  • lrem(name, count, value)

    # 在name对应的list中删除指定的值
    # 参数:
        # name,redis的name
        # value,要删除的值
        # count,count=0,删除列表中所有的指定值;
               # count>0,从前往后删除列表中的个数
               # count<0,从后往前删除列表中的个数
    
  • lpop(name)

    # 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
     
    # 更多:
        # rpop(name) 表示从右向左操作
    
  • lindex(name, index)

    在name对应的列表中根据索引获取列表元素
    
  • lrange(name, start, end)

    # 在name对应的列表分片获取数据
    # 参数:
        # name,redis的name
        # start,索引的起始位置
        # end,索引结束位置  
    print(re.lrange('aa',0,re.llen('aa')))
    
  • ltrim(name, start, end)

    # 在name对应的列表中移除没有在start-end索引之间的值
    # 参数:
        # name,redis的name
        # start,索引的起始位置
        # end,索引结束位置(大于列表长度,则代表不移除任何)
    
  • rpoplpush(src, dst)

    # 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
    # 参数:
        # src,要取数据的列表的name
        # dst,要添加数据的列表的name
    
  • blpop(keys, timeout)

    # 将多个列表排列,按照从左到右去pop对应列表的元素
    # 参数:
        # keys,redis的name的集合
        # timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞
    # 更多:
        # r.brpop(keys, timeout),从右向左获取数据
    爬虫实现简单分布式:多个url放到列表里,往里不停放URL,程序循环取值,但是只能一台机器运行取值,可以把url放到redis中,多台机器从redis中取值,爬取数据,实现简单分布式
    
  • brpoplpush(src, dst, timeout=0)

    # 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧
     
    # 参数:
        # src,取出并要移除元素的列表对应的name
        # dst,要插入元素的列表对应的name
        # timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞
    
  • 自定义增量迭代(生成器的使用场景)

    # 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:
        # 1、获取name对应的所有列表
        # 2、循环列表
    # 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:
    import redis
    conn=redis.Redis(host='127.0.0.1',port=6379)
    # 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])
    # conn.flushall()
    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)
    

集合(set)

"""
sadd key member1 member2 ...
sdiff key1 key2 ...
sdiffstore newkey key1 key2 ...
sinter key1 key2 ...
sunion key1 key2 ...
smembers key
spop key
"""

有序集合(zset)

"""
zadd key grade1 member1 grade2 member2 ...
zincrby key grade member
zrange key start end
zrevrange key start end
"""

哈希类型(hash)

"""
hset key field value
hget key field
hmset key field1 value1 field2 value2 ...
hmget key field1 field2
hkeys key
hvals key
hdel key field
"""

其他操作

  • delete(*names)

    # 根据删除redis中的任意数据类型
    conn.delete(*['age', 'name']) # 0|1
    
  • exists(name)

    # 检测redis的name是否存在
    conn.exists('name') # 0|1
    
  • keys(pattern='*')

    # 根据模型获取redis的name
    # 更多:
        # KEYS * 匹配数据库中所有 key 。
        # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
        # KEYS h*llo 匹配 hllo 和 heeeeello 等。
        # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 
    
  • expire(name ,time)

    # 为某个redis的某个name设置超时时间
    
  • rename(src, dst)

    # 对redis的name重命名为
    
  • move(name, db))

    # 将redis的某个值移动到指定的db下
    
  • randomkey()

    # 随机获取一个redis的name(不删除)
    
  • type(name)

    # 获取name对应值的类型
    
  • scan(cursor=0, match=None, count=None)
    scan_iter(match=None, count=None)

    # 同字符串操作,用于增量迭代获取key
    

管道

redis中没有真正意义上的回滚操作,要想实现事务操作需要使用pipline管道

import redis
 
pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
 
r = redis.Redis(connection_pool=pool)
 
# pipe = r.pipeline(transaction=False)
pipe = r.pipeline(transaction=True)
pipe.multi()
pipe.set('name', 'alex')
pipe.set('role', 'sb')
 
pipe.execute()  # 这句话,才真正的去执行将上面的操作同步到redis中

Django中使用redis

方式一

utils文件夹下,建立redis_pool.py

import redis
POOL = redis.ConnectionPool(host='127.0.0.1', port=6379,password='1234',max_connections=1000)

视图函数中使用:

import redis
from django.shortcuts import render,HttpResponse
from utils.redis_pool import POOL

def index(request):
    conn = redis.Redis(connection_pool=POOL)
    conn.hset('kkk','age',18)

    return HttpResponse('设置成功')
def order(request):
    conn = redis.Redis(connection_pool=POOL)
    conn.hget('kkk','age')

    return HttpResponse('获取成功')

方式二:

安装django-redis模块

pip3 install django-redis

setting里配置:

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

视图函数:

# 1、直接使用cache进行存取,会自动存入redis中
from django.core.cache import cache
cache.set(key, value, timeout)
cache.get(key)
# 2、也可以使用下面的进心存取
from django_redis import get_redis_connection
conn = get_redis_connection('default')
print(conn.hgetall('xxx'))

猜你喜欢

转载自www.cnblogs.com/guanxiying/p/13376012.html