zoukankan      html  css  js  c++  java
  • Redis

    Redis

    一、什么是redis

    redis是一个key-value存储系统

    二、redis的作用

    1、查询速度快:把数据存储到内存中

    2、不需要提交定义好字段

    三、NoSQL分类

    1. memcache
    - 数据存放到内存, 不能落地、持久化,数据断电就没了
    - 支持数据类型太少,只支持字符串
    
    2. MongoDB
    - 数据存放到内存, 解决了数据的持久化
    - 支持多种数据类型
    
    3. redis
    - 数据存放到内存,可以把数据持久化到硬盘,解决了数据的持久化
    - 支持5大数据类型格式:string(字符串)、list(链表)、set(集合)、zset(有序集合)、hash(字典、哈希类型)
    - 单线程
    

    四、Python操作redis

    1、安装模块

    pip3 install redis
    

    2、基本使用

    import redis
    
    conn = redis.Redis(host='localhost', port=6379)  # host与port有默认值
    conn.set('m','string')
    
    

    五、操作string

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

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

    setnx(name, value)

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

    setex(name, time, value)

    # 设置过期时间(数字秒 或 timedelta对象)
    conn.setex('m',5,'string')
    

    psetex( name, time_ms, value)

    # time_ms,过期时间(数字毫秒 或 timedelta对象
    conn.setex('m',5000,'string')
    

    mset(*args, **kwargs)

    # 批量设置
    conn.mset({'m1':'v1','m2':'v2'})
    

    get(name)

    # 取值
    conn.get('m1')   # b'v1',bytes类型
    

    mget(keys, **args)

    # 批量获取
    conn.mget('k1','k2')
    

    getset(name, value)

    # 设置新值并获取原来的值
    

    getrange(key, start, end)

    # 获取子序列(根据字节获取,非字符)前闭后闭区间
    # 参数:
        # name,Redis 的 name
        # start,起始位置(字节)
        # end,结束位置(字节)
    # 如: "汤姆猫" ,0-3表示 "汤"
    conn.getrange('m1',0,3)
    print(conn.getrange('name',0,3).decode('utf-8'))
    

    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 对应的值中
    
    # 返回name对应值的字节长度(一个汉字3个字节)
    

    incr(name, amount=1)

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

    incrbyfloat( name, amount=1.0)

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

    decr( name, amount=1)

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

    append(key, value)

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

    strlen(name)

    # 统计长度
    conn.strlen('m')
    

    六、操作hash

    hset(name, key, value)

    # name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
     
    # 参数:
        # name,redis的name
        # key,name对应的hash中的key
        # value,name对应的hash中的value
     
    # 注:
        # hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)
    

    hmset(name, mapping)

    # 在name对应的hash中批量设置键值对
     
    # 参数:
        # name,redis的name
        # mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
     
    # 如:
        # conn.hmset('xx', {'k1':'v1', 'k2': 'v2'})
    

    hget(name,key)

    # 在name对应的hash中获取根据key获取value
    

    hmget(name, keys, *args)

    # 在name对应的hash中获取多个key的值
     
    # 参数:
        # name,reids对应的name
        # keys,要获取key集合,如:['k1', 'k2', 'k3']
        # *args,要获取的key,如:k1,k2,k3
     
    # 如:
        # r.mget('xx', ['k1', 'k2'])
        # 或
        # print r.hmget('xx', 'k1', 'k2')
    

    hgetall(name)

    # 获取name对应hash的所有键值
    print(conn.hgetall('xxx').get(b'name'))
    

    hlen(name)

    # 获取name对应的hash中键值对的个数
    

    hkeys(name)

    # 获取name对应的hash中所有的key的值
    

    hvals(name)

    # 获取name对应的hash中所有的value的值
    

    hexists(name, key)

    # 检查name对应的hash是否存在当前传入的key
    

    hdel(name,*keys)

    # 将name对应的hash中指定key的键值对删除
    print(conn.hdel('xxx','sex','name'))
    conn.hdel('m1',*['k1','k2'])
    
    

    hincrby(name, key, amount=1)

    # 自增name对应的hash中的指定key的值,不存在则创建key=amount
    # 参数:
        # name,conndis中的name
        # key, hash对应的key
        # amount,自增数(整数)
    # 统计文章阅读数:key是文章id,value是文章阅读数,有一个阅读者,数字加一,固定一个时间,将数据同步到数据库
    

    hincrbyfloat(name, key, amount=1.0)

    # 自增name对应的hash中的指定key的值,不存在则创建key=amount
     
    # 参数:
        # name,redis中的name
        # key, hash对应的key
        # amount,自增数(浮点数)
     
    # 自增name对应的hash中的指定key的值,不存在则创建key=amount
    

    hscan(name, cursor=0, match=None, count=None)

    # 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
     
    # 参数:
        # name,conndis的name
        # cursor,游标(基于游标分批取获取数据)
        # match,匹配指定key,默认None 表示所有的key
        # count,每次分片最少获取个数,默认None表示采用conndis的默认分片个数
     
    # 如:
        # 第一次:cursor1, data1 = conn.hscan('xx', cursor=0, match=None, count=None)
        # 第二次:cursor2, data1 = conn.hscan('xx', cursor=cursor1, match=None, count=None)
        # ...
        # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
    

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

    # 利用yield封装hscan创建生成器,实现分批去redis中获取数据
     
    # 参数:
        # match,匹配指定key,默认None 表示所有的key
        # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
     
    # 如:
        for item in conn.hscan_iter('xx',count=100):
        	print(item)
    
    # hscan_iter源码
        def hscan_iter(self, name, match=None, count=None):
            cursor = '0'
            while cursor != 0:
                cursor, data = self.hscan(name, cursor=cursor,
                                          match=match, count=count)
                for item in data.items():
                    yield item
    

    七、操作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,要插入的数据
        
    # 如果有多个相同的元素,选择最左边的元素,对其的前后操作
    conn.linsert('l1','before',12,777)
    conn.linsert('l1','after',22,666)
    

    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=2,从前到后,删除2个;
                 # count=-2,从后向前,删除2个
    

    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 表示永远阻塞
    
    • 自定义增量迭代
    def l_iter(name, count):
        cursor = 0
        while True:
            li = conn.lrange(name, cursor, cursor + count - 1)
            if not li:
                return
            cursor += count
            for item in li:
                yield item
    
    
    ret = l_iter('t', 100)
    for r in ret:
        print(r)
    

    八、Python操作Redis之连接池

    redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池

    import redis
    
    pool = redis.ConnectionPool(host='127.0.0.1', port=6379,max_connections=1000)
    r = redis.Redis(connection_pool=pool)
    

    九、Django中使用Redis

    1、方式一(在其它web框架也可以使用)

    redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个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('获取成功')
    

    2、方式二

    使用django-redis模块

    (1)安装django-redis

    pip3 install django-redis
    
    

    (2)使用

    # 视图中
    from django_redis import get_redis_connection
    
    def setname(request):
        # 获取一个连接
        conn=get_redis_connection()
        conn.set('name', '测试')
        return HttpResponse('设置成功')
    
  • 相关阅读:
    VS2010 自动跳过代码现象
    Reverse Linked List II 【纠结逆序!!!】
    Intersection of Two Linked Lists
    Linked List Cycle II
    Remove Nth Node From End of List 【另一个技巧,指针的指针】
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Remove Duplicates from Sorted List
    Linked List Cycle
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/linagcheng/p/10181776.html
Copyright © 2011-2022 走看看