深入浅出Redis(一)简介(一)

2015-07-24 07:27:11 · 作者: · 浏览: 4

Redis是什么

官方描述Redis是一个开源的,支持网络、基于内存亦可持久化的日志型键-值仓储。个人认为这样描述过于简单,不足以体现出Redis的强大。Redis比起传统的键-值仓储要强大许多,事实上Redis支持五种数据结构,而传统的键-值存储只是其中之一。要真正认识Redis的强大所在,就必须理解它所支持的五种数据结构,如何操作它们以及它们能够解决哪些类型的问题。
灵活的数据结构只是Redis强大的一方面,另一方面则它的高性能,实在是太快了,有测评说比Memcached还快。Redis的出现,很大程度弥补了memcached这类键-值存储的不足,在部分场合可以对关系数据库起到很好的补充作用。另外,Redis支持大量的客户端API,从java、C到Ruby等,可以从官网http://redis.io/clients查询是否有你需要的API。


Redis基础

既然Redis是一个键-值仓储,我们先来说说键、值。 键(key)是一个标识符,就像程序语里中我们定义一个变量的名字一样,比如a:b:c这个键,其中冒号':'没有特殊含义,跟其它字符一样,但是在实际中可以用做分隔符来更好地维护系统的所有键。值(value)是我们真在关心的内容,它与键(key)绑定在一起,你可以存放一个字符串,一个数字,或者以json或xml格式序列化一个对象,因为Redis并不关心你存放什么东西,它只是以字节数组的形式来保存它们。如:
set people:id001 '{"id":"id001","name":"ZhangSan","age":"21","sex":"male"}'

这里使用set命令把一个值(对象以json格式序列化)存放到键people:zhangsan中去。之后,可以使用get命令查询对应的值:
get people:id001

能不能像关系数据库或文档型数据库那样,基于对象的年龄或性别来查询呢?对不起,不可以,Redis不支持基于对象的属性来查询,因为Redis只是简单的以字节数据的形式来存储,并不关心存放的内容。这既是Redis的限制,同时也成就了它最大的优点:快。
虽然Redis本身不支持基于对象的属性来查询,我们还是可以自己来实现,比如要基于name来查询,我们可以这么做:
hset people:lookup:name ZhangSan id001

把name与id的对应关系保存起来,之后便可以通过name查询到id,再根据id查询对象了。这里我们提出了实现的方案,但在实际中是否值得这么做却需要更多的考虑,毕竟我们还有关系数据库,而且人为的维护这样的依赖关系可不是件容易的事,想想如果删除了一个对象,我们还得更新people:lookup:name这个键。

Redis的五种数据结构

到目前为止,我们已经看到了三个命令,set、get和hset,Redis是如何知道该使用哪一种数据结构的呢?事实上,每种数据结构都单独提供了若干命令,当使用某个具体的命令时,就决定了具体的数据结构了。比如使用set或get命令时,操作的是String类型的值;而使用hset命令时,操作的是Hash类型的值。

Strings

Strings是Redis中最基本的数据类型,但是别被这个名字迷惑了,因为Redis并不关心值是什么,所以你可以存放字符串、数字、十进制串等任何东西,甚至是对象的序列化。就像之前我们使用set命令把值存入键中,再通过get命令取出键对应的值一样,Redis就是这么简单。当然,与Strings相关的命令还有很多,可以到http://redis.io/commands#string查看全部的命令,这里我们就不一一介绍了。
值得强调的是Strings类型还支持位操作,如:
127.0.0.1:6379> setbit mykey 1 1
(integer) 0
127.0.0.1:6379> setbit mykey 2 1
(integer) 0
127.0.0.1:6379> setbit mykey 3 1
(integer) 0
127.0.0.1:6379> setbit mykey 10 1
(integer) 0
127.0.0.1:6379> getbit mykey 3
(integer) 1
127.0.0.1:6379> bitcount mykey
(integer) 4

setbit命令可以设置某个key指定位置为1或0,getbit可以查询key指定位置的值(0或1),bitcount命令可以查询某个key一共有多少为1的十进制位。这里有一篇文章提到有人使用Redis位操作来统计“一天中有多少活跃用户访问”,对于1.3亿的访问量在一台macbook上只用了50ms和16MB的内存就计算出来了,是不是太神奇了。
还有一点,虽然Redis对存放的值并不关心,但有些命令却依赖于值的类型。比如incr、decr等命令,当键的值不是数值的时候就会报错:
127.0.0.1:6379> set mykey 1
OK
127.0.0.1:6379> incr mykey
(integer) 2
127.0.0.1:6379> incr mykey
(integer) 3
127.0.0.1:6379> get mykey
"3"
127.0.0.1:6379> set akey abc
OK
127.0.0.1:6379> incr akey
(error) ERR value is not an integer or out of range

Hash

Hash的存在使的Redis变得更加强大,功能上它类似于Java语言中的Map。对于Hash来说,一个值可以有若干个字段(field),或者叫属性,比起Strings类型使用序列化的方式来存储对象来说,使用Hash来存储对话更加合理:
127.0.0.1:6379> hset people:id001 id id001
(integer) 1
127.0.0.1:6379> hset people:id001 name ZhangSan
(integer) 1
127.0.0.1:6379> hset people:id001 age 21
(integer) 1
127.0.0.1:6379> hset people:id001 sex male
(integer) 1
127.0.0.1:6379> hget people:id001 name
"ZhangSan"

比起Strings,使用Hash来存放对象的一个好处是需要更新某个属性时,不用更新整个对象的序列化字串。

List

List相当于编程语言中的数组,但比数组的操作要灵活很多。List类型在Redis中是有序的,使用lpush和rpush命令可以把元素分别加到数据的左边和右边,lindex命令可以获取指定位置的元素,lrange命令可以获得指定位置区间的多个元素,lpop(rpop)命令删除并返回最左边(最右边)的元素等:
127.0.0.1:6379> lpush mylist b
(integer) 1
127.0.0.1:6379> lpush mylist a
(integer) 2
127.0.0.1:6379> rpush mylist c
(integer) 3
127.0.0.1:6379> rpush mylist d
(in