• redis


    What is redis?

    Redis is an open source (BSD licensed), in-memory data structure store, used as database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.

    安装Redis

    安装环境centos6.5
    
    yum install redis
    
    redis-server看是否能正常进入服务
    
    chkconfig --list |grep redis 检查redis是否开启自动启动
    
    chkconfig redis on 开机自动启动
    
    service redis start 启动服务
    
    redis-cli 连接redis
    

    python连接redis  

    1、操作模式

    redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。

    r = redis.Redis(host="localhost",port=6379)
    
    #测试
    r.set('foo','bar')
    print(r.get('foo'))
    

      

    2、连接池

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

    pool = redis.ConnectionPool(host = "localhost",port = 6379)
    conn = redis.Redis(connection_pool=pool)
    
    #测试
    conn.set('foo','bar')
    print(conn.get('foo'))
    

     

    操作

    1. String操作

    redis中的String在在内存中按照一个name对应一个value来存储。如图:

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

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

     官方解释:Since the SET command options can replace SETNX, SETEX, PSETEX, it is possible that in future versions of Redis these three commands will be deprecated and finally removed.

    SETNX,SETEX,PSETEX这里我们就不说了,下面我们看下set的具体用法

    pool = redis.ConnectionPool(host = "localhost",port = 6379)
    conn = redis.Redis(connection_pool=pool)
    
    conn.set('foo','bar')     #设置值
    print(conn.get('foo'))    #获取值
    
    conn.set('foo','bar_test')  #如果key存在,修改值
    print(conn.get('foo'))
    
    conn.set('hello','world',ex=5) #设置过期时间
    print(conn.get('hello'))
    
    print(conn.get('foo'))
    conn.set('foo','bar',nx = True) #当key存在时,set不执行,相当于插入
    print(conn.get('foo'))
    
    print(conn.get('foo'))
    conn.set('foo','bar',xx = True) #当key存在时,set不执行,相当于修改
    print(conn.get('foo'))
    

     mset(*args, **kwargs) 

    conn.mset(k1='v1',k2 = 'v2')  #批量设置
    print(conn.mget('k1','k2'))  #批量获取
    
    conn.mset({'k3':'v3','k4':'v4'}) #批量设置另外一种方法
    print(conn.mget(['k3','k4']))       #批量获取另外一种方法
    

     getset(name, value)

    Atomically sets key to value and returns the old value stored at key. Returns an error when key exists but does not hold a string value. 

    print(conn.getset('k5','hello'))
    print(conn.get('k5'))
    

    setrange(name, offset, value)  

    Overwrites part of the string stored at key, starting at the specified offset, for the entire length of value. If the offset is larger than the current length of the string at key, the string is padded with zero-bytes to make offset fit. Non-existing keys are considered as empty strings, so this command will make sure it holds a string large enough to be able to set value at offset.

    Note that the maximum offset that you can set is 229 -1 (536870911), as Redis Strings are limited to 512 megabytes. If you need to grow beyond this size, you can use multiple keys.

    print(conn.get('k2'))
    print(conn.setrange('k2',6,'world'))   #根据offest修改值,如果offset的长度超过value本身的长度,则以0填充,不存在的key,就当成空字符串
    print(conn.get('k2'))
    

    getrange(key, start, end) 

    Returns the substring of the string value stored at key, determined by the offsets start and end (both are inclusive). Negative offsets can be used in order to provide an offset starting from the end of the string. So -1 means the last character, -2 the penultimate and so forth.

    The function handles out of range requests by limiting the resulting range to the actual length of the string.

    print(conn.get('k2'))
    print(conn.getrange('k2',6,10))
    print(conn.getrange('k2',-5,-1))  #-1最后,相当于列表,字符串的切片
    

      

    setbit(name, offset, value)

    print(ord('a'))   #字符对应ascii 'a' - 97  二进制01100001
    conn.set('k1','a')  #值设置为a
    conn.setbit('k1',6,1)   #这个是按1个byte来算,第0位就是0,第1位就是1
    conn.setbit('k1',7,0)   #
    
    print(conn.get('k1').decode()) #结果为b
    

      说一种setbit的应用场景,假设我们要保存上亿用户的在线数据以及统计在线用户数,简单的办法是在数据库中新增一个字段来存储在线用户,这样会当数据量大时会导致查找慢

    127.0.0.1:6379> setbit k20 1000 1   #可以把数据库的id与设置的位偏移量对应
    (integer) 0
    127.0.0.1:6379> bitcount k20       #统计在线用户数
    (integer) 1
    127.0.0.1:6379> setbit k20 10000 1
    (integer) 0
    127.0.0.1:6379> bitcount k20
    (integer) 2
    
    #我们来算下1MB能存储多少在线用户数,1M=1024KB = 1024*1024B=1024*1024*8 = 8388608
    1MB就能存下800多万数据,可以说是非常省空间了
    

      

     getbit(name, offset)

    print(conn.getbit('k1',1))   
    print(conn.getbit('k1',3))  

     还有其它的一些函数,incr(整数自增1),decr(整数自减1),incrby(以指定的数自增),decrby(以指定的数自减),incrbyfloat(以指定的数自增float),strlen(得到value的长度),append(添加一个值到key)

    还有一些关于位操作的函数详见https://redis.io/commands#string

    2. Hash操作

    hash表现形式上有些像pyhton中的dict,可以存储一组关联性较强的数据 , redis中Hash在内存中的存储格式如下图:  

    下面对函数的解释均参照redis官网

    HSET(key,field,value)

    Sets field in the hash stored at key to value. If key does not exist, a new key holding a hash is created. If field already exists in the hash, it is overwritten.

    Return value
    • 1 if field is a new field in the hash and value was set.
    • 0 if field already exists in the hash and the value was updated.

    HGET(key,field)

    Returns the value associated with field in the hash stored at key.

    Return value

    Bulk string reply: the value associated with field, or nil when field is not present in the hash or key does not exist.

    print(conn.hset('names','name1','lxj'))  #当key不存在时,新建key,当field不存在,储存field和value。并且返回1
    print(conn.hset('names','name2','sx'))
    print(conn.hget('names','name1'))      #当field存在,返回对应的值
    
    #结果:
    1
    1
    b'lxj'
    
    print(conn.hset('names','name1','LXJ'))  #当key存在时,field存在,修改field对应value。并且返回0
    print(conn.hget('names','name1'))      #当field存在,返回对应的值
    print(conn.hget('names','name3'))      #当field不存在,返回None
    print(conn.hget('k1','name3'))      #当key不存在,返回None
    
    #结果:
    0
    b'LXJ'
    None
    None
    

     

    HSETNX(key,field,value)

    Sets field in the hash stored at key to value, only if field does not yet exist. If key does not exist, a new key holding a hash is created. If field already exists, this operation has no effect.

    Return value

    Integer reply, specifically:

    • 1 if field is a new field in the hash and value was set.
    • 0 if field already exists in the hash and no operation was performed.
    print(conn.hsetnx('names','name1','test'))  #当field存在时,不操作,返回0
    print(conn.hset('names','name3','ss'))   #当field不存在时,储存field和value,相当于添加
    print(conn.hget('names','name3'))      #当field存在,返回对应的值
    print(conn.hget('names','name1'))      #当field存在,返回对应的值
    
    #结果
    0
    1
    b'ss'
    b'LXJ'
    

    批量设置值和获取值(hmset,hmget)

      hmset(key, mapping) 批量设置值

      hmget(name, keys, *args) 批量获取值

    print(conn.hmset('names',{'name2':'SX','name5':'abc'}))  #当field不存在,储存field和value。存在,覆盖field对应的值,返回True
    print(conn.hmget('names','name1',*['name1','name3']))      #当field存在,返回对应的值,返回值列表
    print(conn.hmget('names',['name1','name3']))                 #第二种写法
    print(conn.hmget('names','name1','name3','name5'))            #第三种写法
    
    #结果
    True
    [b'LXJ', b'LXJ', b'ss']
    [b'LXJ', b'ss']
    [b'LXJ', b'ss', b'abc']  

    HVALS(key)

    Returns all values in the hash stored at key.

    HKEYS(key)

    Returns all field names in the hash stored at key.

    print(conn.hkeys('names'))
    print(conn.hvals('names'))
    
    #结果
    [b'name1', b'name2', b'name3', b'name5']
    [b'LXJ', b'SX', b'ss', b'abc']
    

    HGETALL(key)

    Returns all fields and values of the hash stored at key. In the returned value, every field name is followed by its value, so the length of the reply is twice the size of the hash.

    print(conn.hgetall('names'))
    
    #结果
    {b'name3': b'ss', b'name1': b'LXJ', b'name5': b'abc', b'name2': b'SX'}
    

    HLEN(key)

    Returns the number of fields contained in the hash stored at key.

    HSTRLEN(key,field)

    Returns the string length of the value associated with field in the hash stored at key. If the key or the field do not exist, 0 is returned.

    print(conn.hlen('names'))        #返回key下面所有field的数目
    print(conn.hstrlen('names','name3'))  #返回key下field对应的value长度
    结果:
    4
    2
    

     

    HEXISTS(key,field)

    Returns if field is an existing field in the hash stored at key.

    HDEL key field [field ...]

    Removes the specified fields from the hash stored at key. Specified fields that do not exist within this hash are ignored. If key does not exist, it is treated as an empty hash and this command returns 0.

    print(conn.hexists('names','name2'))  #判断field是否在key中,返回True or False
    print(conn.hexists('names','name4'))
    
    结果:
    True
    False
    

    HINCRBY(key,field,increment)

    Increments the number stored at field in the hash stored at key byincrement. If key does not exist, a new key holding a hash is created. If fielddoes not exist the value is set to 0 before the operation is performed.

    The range of values supported by HINCRBY is limited to 64 bit signed integers.

    HINCRBYFLOAT(key,field,increment)

    Increment the specified field of a hash stored at key, and representing a floating point number, by the specified increment. If the increment value is negative, the result is to have the hash field value decremented instead of incremented. If the field does not exist, it is set to 0 before performing the operation. An error is returned if one of the following conditions occur:

    • The field contains a value of the wrong type (not a string).
    • The current field content or the specified increment are not parsable as a double precision floating point number.

    The exact behavior of this command is identical to the one of the INCRBYFLOAT command, please refer to the documentation of INCRBYFLOAT for further information.

    conn.hset('age','lxj','20')
    print(conn.hincrby('age','ss',3))   #如果key或则field不存在,则创建。使用该函数value必须为整数,返回自增后的数
    print(conn.hincrby('age','ss',-3))
    print(conn.hincrby('age','lxj',3))
    
    结果:
    3
    0
    23
    
    conn.hset('age','lxj','20.1')
    print(conn.hincrbyfloat('age','sx1',3))   #如果key或则field不存在,则创建。使用该函数value可以为整数或则浮点数,返回自增后的数且均为浮点数
    print(conn.hincrbyfloat('age','sx1',-3))
    print(conn.hincrbyfloat('age','lxj',3.5))
    
    结果:
    3.0
    0.0
    23.6
    

     

    SCAN(cursor=0, match=None, count=None)

    The SCAN command and the closely related commands SSCAN, HSCAN and ZSCAN are used in order to incrementally iterate over a collection of elements.

    详见https://redis.io/commands/scan。 

    # 增量式迭代获取,对于数据大的数据非常有用,scan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆
     
    # 参数:
        # cursor,游标(基于游标分批取获取数据)
        # match,匹配指定key,默认None 表示所有的key
        # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数,官网上好像是10个
     
    # 如:
        # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
        # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
        # ...
        # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕
    
    
    currsor,data = conn.scan(0,'*')  #cursor游标,类似读取文本的seek,match匹配的模式,count显示几条数据
    #返回的是下一次迭代的新游标和读取出来的列表数据组成的元组
    print(currsor,data)
    currsor1,data1 = conn.scan(currsor,'*')  #读取剩下的数据,直到游标为0表示数据读完
    print(data1)
    #结果
    15 [b'k8', b'names', b'k1', b'k5', b'k3', b'age', b'k2', b'k7', b'k6', b'k9']
    [b'k4']
    

    SSCAN, HSCAN and ZSCAN与scan用法一致,调用参数有些许不同,都要指定key,以hscan为例

    currsor,data = conn.hscan('names',0)  #cursor游标,类似读取文本的seek,简单理解就是鼠标在的位置,match匹配的模式,count显示几条数据
    #返回的是下一次迭代的新游标和读取出来的列表数据组成的元组
    print(currsor,data)
    
    结果:
    0 {b'name5': b'abc', b'name1': b'LXJ', b'name2': b'SX', b'name3': b'ss'}
    

    3. list

    List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:  

    LPUSH(key,*value)

    Insert all the specified values at the head of the list stored at key. If key does not exist, it is created as empty list before performing the push operations. When key holds a value that is not a list, an error is returned.

    It is possible to push multiple elements using a single command call just specifying multiple arguments at the end of the command. Elements are inserted one after the other to the head of the list, from the leftmost element to the rightmost element. So for instance the command LPUSH mylist a b c will result into a list containing c as first element, b as second element and a as third element.

    RPUSH (key,*value)

    Insert all the specified values at the tail of the list stored at key. If key does not exist, it is created as empty list before performing the push operation. When key holds a value that is not a list, an error is returned.

    It is possible to push multiple elements using a single command call just specifying multiple arguments at the end of the command. Elements are inserted one after the other to the tail of the list, from the leftmost element to the rightmost element. So for instance the command RPUSH mylist a b cwill result into a list containing a as first element, b as second element and cas third element.

    LRANGE(key ,start, stop)

    Returns the specified elements of the list stored at key. The offsets startand stop are zero-based indexes, with 0 being the first element of the list (the head of the list), 1 being the next element and so on.

    These offsets can also be negative numbers indicating offsets starting at the end of the list. For example, -1 is the last element of the list, -2 the penultimate, and so on.

    print(conn.lpush('courses',*['python','linux','mysql']))  #lpush相当于从列表左边插入。返回列表长度
    print(conn.lrange('courses',0,-1))                          #相当于切片,此时我们得到的队列顺序应该是mysql - linux - python
    print(conn.rpush('courses',*['redis','sqlalchemy','rabbitmq']))  #lpush相当于从列表的后面(右边)插入。返回列表长度
    print(conn.lrange('courses',0,-1))                         #此时我们得到的队列顺序应该是:之前的列表 - redis - sqlalchemy - rabbitmq
    
    #结果;
    3
    [b'mysql', b'linux', b'python']
    6
    [b'mysql', b'linux', b'python', b'redis', b'sqlalchemy', b'rabbitmq']
    

    LPUSHX(key ,value)

    Inserts value at the head of the list stored at key, only if key already exists and holds a list. In contrary to LPUSH, no operation will be performed when key does not yet exist.

    RPUSHX(key ,value)

    Inserts value at the tail of the list stored at key, only if key already exists and holds a list. In contrary to RPUSH, no operation will be performed when keydoes not yet exist.

    print(conn.lpushx('classes','11'))  #仅当key存在时插入,插入方法同lpush
    print(conn.lrange('classes',0,-1))
    print(conn.rpush('courses','python_test'))  #仅当key存在时插入,插入方法同rpush。返回列表长度
    print(conn.lrange('courses',0,-1))
    
    #结果:
    0
    []
    8
    [b'mysql', b'linux', b'python', b'redis', b'sqlalchemy', b'rabbitmq', b'python_test', b'python_test']
    

      

    LPOP(key)

    Removes and returns the first element of the list stored at key.

    Return value

    Bulk string reply: the value of the first element, or nil when key does not exist.

    RPOP(key)

    Removes and returns the last element of the list stored at key.

    Return value

    Bulk string reply: the value of the last element, or nil when key does not exist.

    print(conn.lrange('courses',0,-1))
    print(conn.lpop('courses'))      #从头部删除value,返回删除的value
    print(conn.rpop('courses'))     #从尾部删除value,返回删除的value
    print(conn.lrange('courses',0,-1))
    
    #结果:
    [b'mysql', b'linux', b'python', b'redis', b'sqlalchemy', b'rabbitmq', b'python_test', b'python_test']
    b'mysql'
    b'python_test'
    [b'linux', b'python', b'redis', b'sqlalchemy', b'rabbitmq', b'python_test']
    

    blpop和brpop时阻塞版的lpop和rpop

    print(conn.lrange('courses',0,-1))
    print(conn.blpop('courses',0))   #阻塞版的lpop,如果list没有数据,则阻塞。可以设置timeout。0表示一直阻塞
    print(conn.brpop('courses',0))   #阻塞版的rpop,如果list没有数据,则阻塞。可以设置timeout。0表示一直阻塞
    
    #结果:
    [b'sqlalchemy', b'rabbitmq', b'python_test']
    (b'courses', b'sqlalchemy')
    (b'courses', b'python_test')  

    具体详见https://redis.io/commands#list

    linsert(self, key, where, refvalue, value)

    LINSERT key BEFORE|AFTER pivot value

    Inserts value in the list stored at key either before or after the reference value pivot.

    When key does not exist, it is considered an empty list and no operation is performed.

    An error is returned when key exists but does not hold a list value.

    Return value

     the length of the list after the insert operation, or -1 when the value pivot was not found.

    print(conn.lrange('courses',0,-1))
    print(conn.linsert('courses','before',0,'python'))  #如果key存在,pivot(标杆)不存在,返回-1
    
    print(conn.lrange('classes',0,-1))
    print(conn.linsert('classes','before',0,'python'))   #如果key不存在,不操作,返回0
    print(conn.lrange('classes',0,-1))
    
    #结果
    [b'rabbitmq']
    -1
    []
    0
    []
    
    
    print(conn.lrange('courses',0,-1))
    print(conn.linsert('courses','before','rabbitmq','python'))  #如果key存在,pivot(标杆)存在,插入值,返回列表长度
    print(conn.linsert('courses','after','rabbitmq','mysql'))  #如果key存在,pivot(标杆)存在,插入值,返回列表长度
    print(conn.lrange('courses',0,-1))
    
    #结果:
    [b'rabbitmq']
    2
    3
    [b'python', b'rabbitmq', b'mysql']
    

    RPOPLPUSH source destination

    Atomically returns and removes the last element (tail) of the list stored atsource, and pushes the element at the first element (head) of the list stored at destination.

    For example: consider source holding the list a,b,c, and destination holding the list x,y,z. Executing RPOPLPUSH results in source holding a,b and destination holding c,x,y,z.

    If source does not exist, the value nil is returned and no operation is performed. If source and destination are the same, the operation is equivalent to removing the last element from the list and pushing it as first element of the list, so it can be considered as a list rotation command.

    Return value

    Bulk string reply: the element being popped and pushed.

    BRPOPLPUSH source destination timeout

    BRPOPLPUSH is the blocking variant of RPOPLPUSH. When source contains elements, this command behaves exactly like RPOPLPUSH. When used inside a MULTI/EXEC block, this command behaves exactly like RPOPLPUSH. When source is empty, Redis will block the connection until another client pushes to it or until timeout is reached. A timeout of zero can be used to block indefinitely.

    See RPOPLPUSH for more information.

    Return value

    Bulk string reply: the element being popped from source and pushed to destination. If timeout is reached, a Null reply is returned.

    print(conn.lrange('courses',0,-1),conn.lrange('classes',0,-1))
    print(conn.rpoplpush('courses','classes'))
    print(conn.lrange('courses',0,-1),conn.lrange('classes',0,-1))
    
    #结果
    [b'python', b'rabbitmq', b'mysql'] []
    b'mysql'
    [b'python', b'rabbitmq'] [b'mysql']
    
    第二次结果
    [b'python', b'rabbitmq'] [b'mysql']
    b'rabbitmq'
    [b'python'] [b'rabbitmq', b'mysql']
    
    第三次
    [b'python'] [b'rabbitmq', b'mysql']
    b'python'
    [] [b'python', b'rabbitmq', b'mysql']
    
    第四次
    [] [b'python', b'rabbitmq', b'mysql']
    None
    [] [b'python', b'rabbitmq', b'mysql']
    
    
    当结果为空的时候,不再继续操作。如果我们用BRPOPLPUSH当pop列表为空时就进入阻塞模式
    print(conn.lrange('courses',0,-1),conn.lrange('classes',0,-1))
    print(conn.brpoplpush('courses','classes'))
    print(conn.lrange('courses',0,-1),conn.lrange('classes',0,-1))
    结果:
    [] [b'python', b'rabbitmq', b'mysql']
    ..到这里程序就阻塞了
    此时我们在redis-cli客户端执行添加value:
    127.0.0.1:6379> lpush courses mysql
    (integer) 1
    
    此时我们看程序已经运行完成了,完整的运行结果
    [] [b'python', b'rabbitmq', b'mysql']
    b'mysql'
    [] [b'mysql', b'python', b'rabbitmq', b'mysql']
    

      

    llen获取列表长度,lindex获取下标对应的值

    print(conn.lrange('courses',0,-1),conn.lrange('classes',0,-1))
    print(conn.llen('classes'))
    print(conn.lindex('classes',1))
    
    #结果
    [] [b'mysql', b'python', b'rabbitmq', b'mysql']
    4
    b'python'
    

    LREM key count value

    Removes the first count occurrences of elements equal to value from the list stored at key. The count argument influences the operation in the following ways:

    • count > 0: Remove elements equal to value moving from head to tail.
    • count < 0: Remove elements equal to value moving from tail to head.
    • count = 0: Remove all elements equal to value.

    For example, LREM list -2 "hello" will remove the last two occurrences of"hello" in the list stored at list.

    Note that non-existing keys are treated like empty lists, so when key does not exist, the command will always return 0.

    Return value

    the number of removed elements.

    print(conn.lpush('classes','mysql','python','mysql','python','rabbitmq','redis','rabbitmq'))
    print(conn.lrange('classes',0,-1))
    print(conn.lrem('classes','mysql'))   #count默认为0,全部删除
    print(conn.lrem('classes','python',-2))  #匹配到的值从后往前删
    print(conn.lrem('classes','rabbitmq',2))  #匹配到的值从前往后删
    
    #结果:
    11
    [b'rabbitmq', b'redis', b'rabbitmq', b'python', b'mysql', b'python', b'mysql', b'mysql', b'python', b'rabbitmq', b'mysql']
    4
    2
    2
    [b'redis', b'python', b'rabbitmq']
    

    LTRIM key start stop

    Trim an existing list so that it will contain only the specified range of elements specified. Both start and stop are zero-based indexes, where 0 is the first element of the list (the head), 1 the next element and so on.

    For example: LTRIM foobar 0 2 will modify the list stored at foobar so that only the first three elements of the list will remain.

    start and end can also be negative numbers indicating offsets from the end of the list, where -1 is the last element of the list, -2 the penultimate element and so on.

    Out of range indexes will not produce an error: if start is larger than the end of the list, or start > end, the result will be an empty list (which causes key to be removed). If end is larger than the end of the list, Redis will treat it like the last element of the list.

    A common use of LTRIM is together with LPUSH / RPUSH. For example:

    LPUSH mylist someelement
    LTRIM mylist 0 99
    

    This pair of commands will push a new element on the list, while making sure that the list will not grow larger than 100 elements. This is very useful when using Redis to store logs for example. It is important to note that when used in this way LTRIM is an O(1) operation because in the average case just one element is removed from the tail of the list.

    print(conn.lpush('classes','mysql','python','mysql','python','rabbitmq','redis'))   #push6条数据
    print(conn.lrange('classes',0,-1))
    print(conn.ltrim('classes',0,2))    #用切片的方法,保留切片的数据(保留前3条),丢弃其它数据
    print(conn.lrange('classes',0,-1))    #通过切片获取元素,不修改列表,仅获取
    #结果:
    6
    [b'redis', b'rabbitmq', b'python', b'mysql', b'python', b'mysql']
    True
    [b'redis', b'rabbitmq', b'python']
    

    4.set集合操作

    Set操作,Set集合就是不允许重复的列表

    SADD key member [member ...]

    Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members.

    An error is returned when the value stored at key is not a set.

    Return value

    Integer reply: the number of elements that were added to the set, not including all the elements already present into the set.

    SMEMBERS key

    Returns all the members of the set value stored at key.

    This has the same effect as running SINTER with one argument key.

    SCARD key

    Returns the set cardinality (number of elements) of the set stored at key.

    print(conn.sadd('num',*[1,2,3,4,5]))   #添加指定的values到key,返回添加成功的个数
    print(conn.sadd('num',*[4,5,6,7,8]))
    print(conn.smembers('num'))   #返回指定key的所有values
    print(conn.scard('num'))      #统计指定key的value个数
    
    #结果:
    5
    3
    {b'3', b'6', b'4', b'2', b'7', b'8', b'5', b'1'}
    8
    

      

    SDIFF key [key ...]

    Returns the members of the set resulting from the difference between the first set and all the successive sets.

    SINTER key [key ...]

    Returns the members of the set resulting from the intersection of all the given sets.

    SUNION key [key ...]

    Returns the members of the set resulting from the union of all the given sets.

    print(conn.sadd('num',*[1,2,3,4,5]))   #添加指定的values到key,返回添加成功的个数
    print(conn.sadd('num',*[4,5,6,7,8]))
    print(conn.sadd('num1',*[3,4,5,6,7,8,9,10]))
    print(conn.sdiff('num','num1'))   #返回在num而不在num的值,即集合中的差集
    print(conn.sinter('num','num1'))  #集合中的交集,返回num和num1的交集。这里key可以有好多个。
    print(conn.sunion('num','num1'))  #集合中的并集,返回num和num1的并集
    
    结果:
    5
    3
    8
    {b'1', b'2'}
    {b'3', b'5', b'4', b'7', b'6', b'8'}
    {b'3', b'1', b'9', b'5', b'4', b'10', b'7', b'2', b'6', b'8'}  

    SDIFFSTORE destination key [key ...]

    This command is equal to SDIFF, but instead of returning the resulting set, it is stored in destination.

    If destination already exists, it is overwritten.

    SINTERSTORE destination key [key ...]

    This command is equal to SINTER, but instead of returning the resulting set, it is stored in destination.

    If destination already exists, it is overwritten.

    SUNIONSTORE destination key [key ...]

    This command is equal to SUNION, but instead of returning the resulting set, it is stored in destination.

    If destination already exists, it is overwritten.

    print(conn.sdiffstore('num3','num','num1'))   #返回在num而不在num1的个数,并添加到指定的key(num3)中
    print(conn.sinterstore('num4','num','num1'))  #集合中的交集,返回num和num1的交集个数。这里key可以有好多个。并添加到指定的key(num4)中
    print(conn.sunionstore('num5','num','num1'))  #集合中的并集,返回num和num1的并集个数
    print(conn.smembers('num3'),conn.smembers('num4'),conn.smembers('num4'))
    
    #结果
    2
    6
    10
    {b'1', b'2'} {b'3', b'4', b'6', b'5', b'7', b'8'} {b'3', b'4', b'6', b'5', b'7', b'8'}
    

      

      

    SISMEMBER key member

    Returns if member is a member of the set stored at key.

    SREM key member [member ...]

    Remove the specified members from the set stored at key. Specified members that are not a member of this set are ignored. If key does not exist, it is treated as an empty set and this command returns 0.

    An error is returned when the value stored at key is not a set.

    SMOVE source destination member

    Move member from the set at source to the set at destination. This operation is atomic. In every given moment the element will appear to be a member of source or destination for other clients.

    If the source set does not exist or does not contain the specified element, no operation is performed and 0 is returned. Otherwise, the element is removed from the source set and added to the destination set. When the specified element already exists in the destination set, it is only removed from the source set.

    An error is returned if source or destination does not hold a set value.

    print(conn.smembers('num'))
    print(conn.sismember('num',3))     #判断值是否存在,返回True 或False
    print(conn.srem('num',*[1,2,3]))     #删除一个或多个值,返回删除的元素个数
    print(conn.smove('num','num7',5))  #删除一个值并存储到另外一个集合中,如果值存在,返回True
    print(conn.smembers('num'),conn.smembers('num7'))
    
    #结果
    {b'5', b'1', b'6', b'8', b'2', b'7', b'3'}
    True
    3
    True
    {b'7', b'8', b'6'} {b'5', b'4'}
    

      

    SPOP key [count]

    Removes and returns one or more random elements from the set value store at key.

    This operation is similar to SRANDMEMBER, that returns one or more random elements from a set but does not remove it.

    SRANDMEMBER key [count]

    When called with just the key argument, return a random element from the set value stored at key.

    Starting from Redis version 2.6, when called with the additional countargument, return an array of count distinct elements if count is positive. If called with a negative count the behavior changes and the command is allowed to return the same element multiple times. In this case the number of returned elements is the absolute value of the specified count.

    When called with just the key argument, the operation is similar to SPOP, however while SPOP also removes the randomly selected element from the set, SRANDMEMBER will just return a random element without altering the original set in any way.

    print(conn.smembers('num1'))
    print(conn.spop('num1'))  #随机删除一个元素
    print(conn.spop('num1'))
    print(conn.srandmember('num1',2))  #从key对应的集合中随机获取 numbers 个元素,返回列表形式
    print(conn.smembers('num1'))
    
    #结果
    {b'7', b'6', b'5', b'8', b'10', b'9', b'3', b'4'}
    b'8'
    b'3'
    [b'7', b'10']
    {b'7', b'6', b'5', b'10', b'9', b'4'}

    SSCAN key cursor [MATCH pattern] [COUNT count]

    详见scan

    有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。  

    详见https://redis.io/commands#sorted_set

    其它常用操作

    delete(*names)
    # 根据删除redis中的任意数据类型
    
    exists(name)
    # 检测redis的name是否存在
    
    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-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。

    pipe = conn.pipeline(transaction=True)
    
    pipe.set('name','lxj')
    pipe.set('role','it')
    pipe.execute()
    

    发布订阅

    发布者:服务器

    订阅者:Dashboad和数据处理

    功能和rabbitmq相似,但是实现过程要简单很多

    import redis
    
    class RedisHelper(object):
        def __init__(self):
            self.__pool = redis.ConnectionPool(host="localhost", port=6379)
            self.__conn = redis.Redis(connection_pool=self.__pool)
            self.chan_sub = 'fm104.5'   #约定订阅者的频道
            self.chan_pub = 'fm104.5'   #约定发布者的频道
    
        def public(self,msg):
            return self.__conn.publish(self.chan_pub,msg)  #根据频道发送消息
    
        def subscribe(self):
            pub = self.__conn.pubsub()  #可以理解打开收音机
            pub.subscribe(self.chan_sub) #调频
            pub.parse_response() #准备接收
            return pub
    

      

    发布者

    from redis_helper import RedisHelper
    
    obj = RedisHelper()
    while True:
        msg = input(">>")
        obj.public(msg)   #发布消息
    

      

    订阅者  

    from redis_helper import RedisHelper
    
    obj = RedisHelper()
    redis_sub = obj.subscribe()
    
    while True:
        msg = redis_sub.parse_response()  #开始接收
        print(msg)
    

      更多res操作详见:https://redis.io/documentation

    什么时候用关系型数据库,什么时候 用NoSQL?

     


    Go for legacy relational databases (RDBMS) when:

    1. The data is well structured, and lends itself to a tabular arrangement (rows and columns) in a relational database. Typical examples: bank account info, customer order info, customer info, employee info, department info etc etc.
    2. Another aspect of the above point is : schema oriented data model. When you design a data model (tables, relationships etc) for a potential use of RDBMS, you need to come up with a well defined schema: there will be these many tables, each table having a known set of columns that store data in known typed format (CHAR, NUMBER, BLOB etc).
    3. Very Important: Consider whether the data is transactional in nature. In other words, whether the data will be stored, accessed and updated in the context of transactions providing the ACID semantics or is it okay to compromise some/all of these properties.
    4. Correctness is also important and any compromise is _unacceptable_. This stems from the fact that in most NoSQL databases, consistency is traded off in favor of performance and scalability (points on NoSQL databases are elaborated below).
    5. There is no strong/compelling need for a scale out architecture ; a database that linearly scales out (horizontal scaling) to multiple nodes in a cluster.
    6. The use case is not for “high speed data ingestion”.
    7. If the client applications are expecting to quickly stream large amounts of data in/out of the database then relational database may not be a good choice since they are not really designed for scaling write heavy workloads.
    8. In order to achieve ACID properties, lots of additional background work is done especially in writer (INSERT, UPDATE, DELETE) code paths. This definitely affects performance.
    9. The use case is not for “storing enormous amounts of data in the range of petabytes”.

    Go for NoSQL databases when:

    1. There is no fixed (and predetermined) schema that data fits in:
    2. Scalability, Performance (high throughput and low operation latency), Continuous Availability are very important requirements to be met by the underlying architecture of database.
    3. Good choice for “High Speed Data Ingestion”. Such applications (for example IoT style) which generate millions of data points in a second and need a database capable of providing extreme write scalability.
    4. The inherent ability to horizontally scale allows to store large amounts of data across commodity servers in the cluster. They usually use low cost resources, and are able to linearly add compute and storage power as the demand grows.

    source page https://www.quora.com/When-should-you-use-NoSQL-vs-regular-RDBMS

      

      

      

      

      



     

  • 相关阅读:
    API下载文件
    c# 测试网络连接
    C# Word 插入签名图片
    c# word文档合并
    c# 文件筛选
    e
    基本初等函数(Basic elementary function)
    前端性能优化学习
    解决点击穿透的最佳实践
    ObjectARX通过选定的实体获取所有组名示例
  • 原文地址:https://www.cnblogs.com/zj-luxj/p/8031127.html
Copyright © 2020-2023  润新知