redis实战[python代码](二)

redis命令

字符串

字符串的自增命令和自减命令

命令 用例和描述
INCR INCR key-name 自增1
DECR DECR key-name 自减1
INCRBY INCRBY key-name amount 加上特定整数
DECRBY DECRBY key-name amount 减去特定的数
INCRBYFLOAT INCRBYFLOAT key-name amount 加上特定的浮点数

测试:

import redis
re = redis.Redis(host='127.0.0.1', port=6379,db=0)

re.incr('key-value')
print(
re.get('key-value'),
re.incr('key-value',15),
re.decr('key-value',5),
re.get('key-value'),
re.set('key-value',13),
re.incr('key-value')
)

结果:
b’15’ 30 25 b’25’ True 14

可以看出:如果用户对一个不存在的键或者一个保存了空串的键执行自增/自减操作,那么redis会将这个键当作是0来处理。
如果这个串无法被解释为整数或者浮点数,那么会报错。
即使在设置键时输入的值为字符串,但只要这个值可以被解释为整数,我们就可以当成整数处理

处理子串和二进制位的命令

命令 用例和描述
APPEND APPEND key-name value 追加值到key-nema存储值的末尾
GETRANGE GETRANGE key-name start end 获取一个偏移量start到end范围内所有字符组成的子串
SETRANGE SETRANGE key-name offset value 将从start偏移量开始的子串设置为给定值
GETBIT GETBIT key-name offset 将字节串看作二进制位串,并返回位串中偏移量为offset的二进制位的值
SETBIT SETBIT key-name offset value 将字节串看作是二进制位串,并将串中偏移量为offset的二进制位值设置为value

测试

127.0.0.1:6379> append new-key hello
(integer) 5
127.0.0.1:6379> append new-key world!
(integer) 11
127.0.0.1:6379> substr new-key 3 7
"lowor"
127.0.0.1:6379> setrange new 0 H
(integer) 1
127.0.0.1:6379> setrange new-key 0 h
(integer) 11
127.0.0.1:6379> setrange new-key 6 w
(integer) 11
127.0.0.1:6379> get new-key
"hellowwrld!"
127.0.0.1:6379> setrange new-key 11 how old are you
(error) ERR wrong number of arguments for 'setrange' command
127.0.0.1:6379> setrange new-key 1 how old are you
(error) ERR wrong number of arguments for 'setrange' command
127.0.0.1:6379> setrange new-key 1 'how old are you'
(integer) 16
127.0.0.1:6379> get new-key
"hhow old are you"
127.0.0.1:6379> setbit new-key 2 1
(integer) 1
127.0.0.1:6379> get new-key
"hhow old are you"
127.0.0.1:6379> setbit another-key 2 1
(integer) 0
127.0.0.1:6379> setbit another-key 7 1
(integer) 0
127.0.0.1:6379> get another-key
"!"

从中可以看出,Redis索引从0开始;
SETRANGE既可以用于替换字符,也可以用于增长字符串;
SETBIT命令会返回二进制位被设置之前的值;
setbit通过将2和7设置为1,也就是说26+21=33,这就是编码为33的字符!

根据以上的命令来看,redis可以非常强大的实现字符串的增删,比一般的数据库强很多。

列表

Redis的列表允许用户从序列两端推入或者弹出元素,获取列表元素,以及执行各种常见的列表操作。

一些常用的列表命令

命令 用例和描述
RPUSH RPUSH key-name value [value…] 将一个或者多个值推入列表的右端
LPUSH LPUSH key-name value [value…] 将一个或者多个值推入列表的左端
RPOP RPOP key-name 移除并且返回列表最右端的元素
LPOP LPOP key-name 移除并且返回列表最左端的元素
LINDEX LINDEX key-name offset 返回列表中偏移量为offset的元素
LRANGE LRANGE key-name start end 返回列表中偏移量从start到end范围的元素
LTRIM LTRIM key-name start end 对列表进行修剪,只保留从start偏移量到end偏移量之内的元素

测试:

127.0.0.1:6379> rpush key last
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> rpush list-key last
(integer) 3
127.0.0.1:6379> lpush list-key first
(integer) 4
127.0.0.1:6379> lrange list-key 0 -1
1) "first"
2) "item"
3) "item"
4) "last"
127.0.0.1:6379> lpop list-key
"first"
127.0.0.1:6379> lpop list-key
"item"
127.0.0.1:6379> ltrim list-key  2 -1
OK
127.0.0.1:6379> lrange list-key 0 -1
(empty list or set)
127.0.0.1:6379>

分析:
依然不能操作"key";组合使用ltrim命令和lrange命令可以一次返回并且弹出多个元素

集合

Redis的集合以无序的方式存储各不相同的元素,用户可以快速对于集合执行添加元素、移除元素以及检查操作。
一些常用的集合命令

命令 用例和描述
SADD SADD key-name item [item…] 将一个或者多个元素添加到集合里面,并且返回新的元素数量
SREM SREM key-name item [item…] 从集合中移除一个或者多个元素,返回被移除元素数量
SISMEMBER SISMEMBER key-name item 检查元素item是否存在于集合key-name中
SCARD SCARD key-name 返回集合包含的元素数量
SMEMBERS SMEMBERS key-name 返回集合包含的所有元素
SRANDMEMBER SRANDMEMBER key-name [count]从集合中随机返回一个或者多个元素
SMOVE SMOVE source-key dest-key item 如果集合source-key包含元素item,那么移除元素item并且添加到dest-key中,成功返回1,否则返回0

测试:

127.0.0.1:6379> sadd set-key a b c
(integer) 3
127.0.0.1:6379> srem set-key c d
(integer) 1
127.0.0.1:6379> srem set-key c d
(integer) 0
127.0.0.1:6379> scard set-key
(integer) 2
127.0.0.1:6379> smembers set-key
1) "b"
2) "a"
127.0.0.1:6379> smove set-key set-key2 a
(integer) 1
127.0.0.1:6379> smove set-key set-key2 c
(integer) 0
127.0.0.1:6379> smembers set-key2
1) "a"
127.0.0.1:6379>

值得注意的是,因为python客户端的bug,srem函数会返回布尔值而不是集合的移除元素数量

处理多个集合的命令

命令 用例和描述
SDIFF SDIFF key-name [key-name…] 返回存在于第一个集合,但是不存在于其它集合的元素(差集运算)
SINTER SINTER key-name [key-name] 返回同时存在于所有集合的元素(交集运算)
SINTERSTORE SINTERSTORE dest-key key-name 将同时存在于所有集合的元素存储到dest-key中
SUNION SUNION key-name [key-name] 返回至少存在于一个集合中的元素
SUNIONSTORE SUNIONSTORE dest-key key-name [key-name] 将至少存在于一个集合的元素,存储到dest-key键中

测试:

127.0.0.1:6379> sadd skey1 a b c d
(integer) 4
127.0.0.1:6379> sadd skey2 c d e f
(integer) 4
127.0.0.1:6379> sdiff skey1 skey2
1) "b"
2) "a"
127.0.0.1:6379> sinter skey1 skey2
1) "d"
2) "c"
127.0.0.1:6379> sunion skey1 skey2
1) "e"
2) "f"
3) "b"
4) "c"
5) "d"
6) "a"

散列

散列可以让用户将多个键值对存储到一个redis键中。

用于添加和删除键值对的散列操作命令

命令 用例和描述
HMGET HMGET key-name key [key …] 从散列中获取一个或者多个键的值
HMSET HMSET key-name key value [key value] … 为散列里面一个或者多个键设置值
HDEL HDEL key-name key [key …] 删除散列里面一个或者多个键值对,返回成功数量
HLEN HLEN key-name 返回散列包含的键值对数量

测试如下:

127.0.0.1:6379> hmset hash-key k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> hmget hash-key
(error) ERR wrong number of arguments for 'hmget' command
127.0.0.1:6379> hmget hash-key k2 k3 k1
1) "v2"
2) "v3"
3) "v1"
127.0.0.1:6379> hlen hash-key
(integer) 4
127.0.0.1:6379> hdel hash-key k1 k3
(integer) 2
127.0.0.1:6379>

展示redis散列的更高级特性

命令 用例和描述
HEXISTS HEXISTS key-name key 检查给定键是否存在于散列中
HKEYS HKEYS key-name 获取散列包含的所有键
HVALS HVALS key-name 获取散列包含的所有键
HGETALL HGETALL key-name 获取散列包含的所有键值对
HINCRBY HINCRBY key-name key increment 将key存储的值加上整数increment
HINCRBYFLOAT HINCRBYFLOAT key-name key increment 将key存储的值加上浮点数increment

测试:

127.0.0.1:6379> hmset hash-key2 short hello long 1000*'1'
OK
127.0.0.1:6379> hkeys hash-key2
1) "short"
2) "long"
127.0.0.1:6379> hgetall hash-key2
1) "short"
2) "hello"
3) "long"
4) "1000*1"
127.0.0.1:6379> hexists hash-key2 num
(integer) 0
127.0.0.1:6379> hincrby hash-key2 num
(error) ERR wrong number of arguments for 'hincrby' command
127.0.0.1:6379> hincrby hash-key2 'num'
(error) ERR wrong number of arguments for 'hincrby' command
127.0.0.1:6379> hincrby hash-key3 num 1
(integer) 1

在考察散列的时候,可以使用hkeys命令,只取出散列包含的键,避免传输体积较大的值。
和字符串一样,对于散列中一个尚未存在的键自增,会将当前的键当作0来处理。
使用python测试如下图所示:

####有序集合
和散列存储着键与值之间的映射类似,有序集合也存储着成员与分值之间的映射,并且提供了分值处理命令,以及根据分值获取或者扫描成员和分值的命令。

一些常用的有序集合命令

命令 用例和描述
ZADD 添加到有序集合中
ZREM 从有序集合移除给定成员
ZCARD 返回有序集合包含的成员数量
ZINCRBY 将member成员分值加上increment
ZCOUNT 返回介于max与min之间的成员数量
ZRANGE 返回介于start与stop之间的成员

发布与订阅模式subscribe/publish

发布与订阅(又称pub/sub)的特点是订阅者(listener)负责订阅频道(channel),发送者(publisher)负责向频道发送二进制字符串消息(binary string message)。每当有消息被发送至给定频道时,频道的所有订阅者都会接收到消息。

也可以把频道看作是电台,其中订阅者可以同时收听多个电台,而发送者则可以在任何电台发送消息。

1.发布与订阅命令

subscribe
subscribe channel [channel …]
订阅给定的一个或多个频道

unsubscribe
unsubscribe [channel [channel …]]
退订给定的一个或多个频道,如果执行时没有给定任何频道,那么退订所有频道

publish
publish channel message
向给定频道发送消息

psubcribe
psubcribe pattern [pattern …]
订阅与给定模式相匹配的所有频道

punsubcribe
punsubcribe [pattern [pattern …]]
退订给定的模式,如果执行时没有给定任何模式,那么退订所有模式

示例代码如下:

import time
import threading
import unittest
"""
发布者
"""
def publisher(conn, n):
    # 在刚开始执行时先休眠,让订阅者有足够的时间来连接服务器并监听消息
    time.sleep(1)
    for i in xrange(n):
        conn.publish('channel', i)
        # 发布消息之后进行短暂的休眠,让消息可以一条一条地出现
        time.sleep(1)
 
"""
发布订阅模式
"""
def runPubsub(conn):
    # 启动发送者线程发送3条消息
    threading.Thread(target=publisher, args=(conn,3,)).start()
    # 创建发布与订阅对象,并让它订阅给定的频道
    pubsub = conn.pubsub()
    pubsub.subscribe(['channel'])
    count = 0
    # 通过遍历函数pubsub.listen()执行结果来监听订阅消息
    for item in pubsub.listen():
        print item
        count += 1
        if count == 4:
            # 在接收到一条订阅反馈消息和三条发布者发送消息之后,执行退订操作,停止监听新消息
            pubsub.unsubscribe()
        # 客户端在接收到退订反馈消息之后就不再接收消息
        if count == 5:
            break
 
"""
测试
"""
class TestRedisPubSub(unittest.TestCase):
    def setUp(self):
        import redis
        self.conn = redis.Redis(db=15)
    
    def tearDown(self):
        del self.conn
        print
        print
 
    def testRunPubsub(self):
        runPubsub(self.conn)
 
if __name__ == '__main__':
    unittest.main()

虽然redis的发布订阅模式很有用,但我们比较少用,主要原因有以下:

(1)与redis的稳定性有关。对于旧版redis来说,如果客户端订阅了某个或某些频道,读取的消息速度不够快,不断积压的消息会使redis输出缓冲区的体积变得越来越大,导致redis速度变慢甚至直接崩溃,也可能导致操作系统强制杀死进程,或者操作系统直接不可用。

新版的redis会自动断开不符合client-output-buffer-limit pubsub配置选项要求的订阅客户端。

(2)和数据传输的可靠性有关。任何网络系统在执行操作时都有可能会遇到断线情况,如果客户端在执行订阅操作的过程中断线,那么客户端将丢失在断线期间发送的所有消息。

如果喜欢简单易用的pushlish命令和subscribe命令,并且可以承担可能会丢失一部分数据的风险,那么也可以继续使用redis提供的发布和订阅特性。

发布了165 篇原创文章 · 获赞 24 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/treblez/article/details/104860725