几乎所有的主流编程语言都有Redis的客户端(http://redis.io/clients),
不考虑Redis非常流行的原因,如果站在技术的角度看原因还有两个:
例如客户端发送一条set hello world命令给服务端,按照RESP 的标准,客户端需要将其封装为如下格式(每行用\r\n分隔):
*3 $3 SET $5 hello $5 world
这样Redis服务端能够按照RESP将其解析为set hello world命令,执行后 回复的格式如下:
+OK
可以看到除了命令(set hello world)和返回结果(OK)本身还包含了 一些特殊字符以及数字,下面将对这些格式进行说明。
RESP的规定一条命令的格式如下,CRLF代表"\r\n"。
*<参数数量> CRLF $<参数1的字节数量> CRLF <参数1> CRLF ... $<参数N的字节数量> CRLF <参数N> CRLF
依然以set hell world这条命令进行说明。 参数数量为3个,因此第一行为:
*3 参数字节数分别是355,因此后面几行为: $3 SET $5 hello $5 world
有一点要注意的是,上面只是格式化显示的结果,实际传输格式为如下 代码,整个过程如图4-1所示:
*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$5\r\nworld\r\n
2.返回结果格式 Redis的返回结果类型分为以下五种,如图4-2所示:
我们知道redis-cli只能看到最终的执行结果,那是因为redis-cli本身就是 按照RESP进行结果解析的,所以看不到中间结果,redis-cli.c源码对命令结 果的解析结构如下:
static sds cliFormatReplyTTY(redisReply *r, char *prefix) { sds out = sdsempty(); switch (r->type) { case REDIS_REPLY_ERROR: // 处理错误回复 case REDIS_REPLY_STATUS: // 处理状态回复 case REDIS_REPLY_INTEGER: // 处理整数回复 case REDIS_REPLY_STRING: // 处理字符串回复 case REDIS_REPLY_NIL: // 处理空 case REDIS_REPLY_ARRAY: // 处理多条字符串回复 return out; }
例如执行set hello world,返回结果是OK,并不能看到加号:
127.0.0.1:6379> set hello world OK
为了看到Redis服务端返回的“真正”结果,可以使用nc命令、telnet命 令、甚至写一个socket程序进行模拟。
下面以nc命令进行演示,首先使用 nc127.0.0.16379连接到Redis:
nc 127.0.0.1 6379
状态回复:set hello world的返回结果为+OK:
set hello world +OK
错误回复:由于sethx这条命令不存在,那么返回结果就是"-"号加上错误消息:
sethx -ERR unknown command 'sethx'
整数回复:当命令的执行结果是整数时,返回结果就是整数回复,例如 incr、exists、del、dbsize返回结果都是整数,例如执行incr counter返回结果 就是“:”加上整数:
incr counter :1
字符串回复:当命令的执行结果是字符串时,返回结果就是字符串回复。
例如get、hget返回结果都是字符串,例如get hello的结果为
“$5\r\nworld\r\n”: get hello $5 world
多条字符串回复:当命令的执行结果是多条字符串时,返回结果就是多条字符串回复。
例如mget、hgetall、lrange等命令会返回多个结果,例如下面操作:
首先使用mset设置多个键值对:
mset java jedis python redis-py +OK
然后执行mget命令返回多个结果,第一个*\2代表返回结果的个数,后面的格式是和字符串回复一致的:
mget java python *2 $5 252 jedis $8 redis-py
有一点需要注意,无论是字符串回复还是多条字符串回复,如果有nil值,那么会返回$-1。
例如,对一个不存在的键执行get操作,返回结果为:
get not_exist_key $-1
如果批量操作中包含一条为nil值的结果,那么返回结果如下:
mget hello not_exist_key java *3 $5 world $-1 $5 jedis
有了RESP提供的发送命令和返回结果的协议格式,各种编程语言就可以利用其来实现相应的Redis客户端,后面两节将介绍Java和Python两个编程 语言的Redis客户端。
Redis官网提供了很多Python语言的客户端 (http://redis.io/clients#python),但最被广泛认可的客户端是redis-py。 redis-py需要Python2.7以上版本,有关Python的安装本书不会介绍,主要介绍 一下如何获取安装redis-py,方法有三种:
第一,使用pip进行安装:
pip install redis
第二,使用easy_install进行安装:
easy_install redis
第三,使用源码安装:以2.10.5版本为例子进行说明,只需要如下四 步:
wget https:// github.com/andymccurdy/redis-py/archive/2.10.5.zip unzip redis-2.10.5.zip cd redis-2.10.5 #安装redis-py python setup.py install
redis-py的使用方法也比较简单,下面将逐步骤介绍。
import redis
client = redis.StrictRedis(host='127.0.0.1', port=6379)
# True client.set(key, "python-redis") # world client.get(key)
整个实例代码如下:
pythonimport redis
client = redis.StrictRedis(host='127.0.0.1', port=6379)
key = "hello"
setResult = client.set(key, "python-redis")
print setResult
value = client.get(key)
print "key:" + key + ", value:" + value
输出结果为:
True
key:hello, value:python-redis
下面代码给出redis-py操作Redis五种数据结构的示例,输出结果写在注释中:
#1.string #输出结果:True client.set("hello","world") #输出结果:world client.get("hello") #输出结果:1 client.incr("counter") #2.hash client.hset("myhash","f1","v1") client.hset("myhash","f2","v2") #输出结果:{'f1': 'v1', 'f2': 'v2'} client.hgetall("myhash") #3.list client.rpush("mylist","1") client.rpush("mylist","2") client.rpush("mylist","3") #输出结果:['1', '2', '3'] client.lrange("mylist", 0, -1) #4.set client.sadd("myset","a") client.sadd("myset","b") client.sadd("myset","a") #输出结果:set(['a', 'b']) client.smembers("myset") #5.zset client.zadd("myzset","99","tom") client.zadd("myzset","66","peter") client.zadd("myzset","33","james") #输出结果:[('james', 33.0), ('peter', 66.0), ('tom', 99.0)] client.zrange("myzset", 0, -1, withscores=True)
redis-py支持Redis的Pipeline功能,下面用一个简单的示例进行说明。
import redis client = redis.StrictRedis(host='127.0.0.1', port=6379)
transaction=False代表不使用事务: pipeline = client.pipeline(transaction=False)
pipeline.set("hello","world") pipeline.incr("counter")
#[True, 3] result = pipeline.execute()
和4.2.4小节一样,将用redis-py的Pipeline实现mdel功能:
import redis def mdel( keys ): client = redis.StrictRedis(host='127.0.0.1', port=6379) pipeline = client.pipeline(transaction=False) for key in keys: print pipeline.delete(key) return pipeline.execute();
redis-py中执行Lua脚本和redis-cli十分类似,redis-py提供了三个重要的 函数实现Lua脚本的执行:
eval(String script, int keyCount, String... params) script_load(String script) evalsha(String sha1, int keyCount, String... params:
eval函数有三个参数,分别是:
return redis.call('get',KEYS[1])
在redis-py中执行,方法如下:
import redis client = redis.StrictRedis(host='127.0.0.1', port=6379) script = "return redis.call('get',KEYS[1])" #输出结果为world print client.eval(script,1,"hello")
script_load和evalsha函数要一起使用,首先使用script_load将脚本加载到 Redis中,代码如下:
scriptSha = client.script_load(script)
evalsha函数用来执行脚本的哈希值,它需要三个参数:
print jedis.evalsha(scriptSha, 1, "hello");
完整代码如下:
pythonimport redis
client = redis.StrictRedis(host='127.0.0.1', port=6379)
script = "return redis.call('get',KEYS[1])"
scriptSha = client.script_load(script)
print client.evalsha(scriptSha, 1, "hello");
本文作者:Eric
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!