字符串类型
这是最简单Redis类型。如果你只用这种类型,Redis就像一个可以持久化的memcached服务器(注:memcache的数据仅保存在内存中,服务器重启后,数据将丢失)。
我们来玩儿一下字符串类型:
$ redis-cli set mykey "my binary safe value"
OK
$ redis-cli get mykey
my binary safe value
正如你所见到的,通常用SET command 和 GET command来设置和获取字符串值。
值可以是任何种类的字符串(包括二进制数据),例如你可以在一个键下保存一副jpeg图片。值的长度不能超过1GB。
虽然字符串是Redis的基本值类型,但你仍然能通过它完成一些有趣的操作。例如:原子递增:
$ redis-cli set counter 100
OK $ redis-cli incr counter
(integer) 101
$ redis-cli incr counter
(integer) 102
$ redis-cli incrby counter 10
(integer) 112
INCR 命令将字符串值解析成整型,将其加一,最后将结果保存为新的字符串值,类似的命令有INCRBY, DECR and DECRBY。实际上他们在内部就是同一个命令,只是看上去有点儿不同。
INCR是原子操作意味着什么呢?就是说即使多个客户端对同一个key发出INCR命令,也决不会导致竞争的情况。例如如下情况永远不可能发生:『客户端1和客户端2同时读出“10”,他们俩都对其加到11,然后将新值设置为11』。最终的值一定是12,read-increment-set操作完成时,其他客户端不会在同一时间执行任何命令。
对字符串,另一个的令人感兴趣的操作是GETSET命令,行如其名:他为key设置新值并且返回原值。这有什么用处呢?例如:你的系统每当有新用户访问时就用INCR命令操作一个Redis key。你希望每小时对这个信息收集一次。你就可以GETSET这个key并给其赋值0并读取原值。 列表类型
要说清楚列表数据类型,最好先讲一点儿理论背景,在信息技术界List这个词常常被使用不当。例如”Python Lists”就名不副实(名为Linked Lists),但他们实际上是数组(同样的数据类型在Ruby中叫数组)
一般意义上讲,列表就是有序元素的序列:10,20,1,2,3就是一个列表。但用数组实现的List和用Linked List实现的List,在属性方面大不相同。
Redis lists基于Linked Lists实现。这意味着即使在一个list中有数百万个元素,在头部或尾部添加一个元素的操作,其时间复杂度也是常数级别的。用LPUSH 命令在十个元素的list头部添加新元素,和在千万元素list头部添加新元素的速度相同。
那么,坏消息是什么?在数组实现的list中利用索引访问元素的速度极快,而同样的操作在linked list实现的list上没有那么快。
Redis Lists are implemented with linked lists because for a database system it is crucial to be able to add elements to a very long list in a very fast way. Another strong advantage is, as you’ll see in a moment, that Redis Lists can be taken at constant length in constant time.
Redis Lists用linked list实现的原因是:对于数据库系统来说,至关重要的特性是:能非常快的在很大的列表上添加元素。另一个重要因素是,正如你将要看到的:Redis lists能在常数时间取得常数长度。 Redis lists 入门
LPUSH 命令可向list的左边(头部)添加一个新元素,而RPUSH命令可向list的右边(尾部)添加一个新元素。最后LRANGE 命令可从list中取出一定范围的元素
$ redis-cli rpush messages "Hello how are you?"
OK
$ redis-cli rpush messages "Fine thanks. I‘m having fun with Redis"
OK
$ redis-cli rpush messages "I should look into this NOSQL thing ASAP"
OK
$ redis-cli lrange messages 0 2
1. Hello how are you?
2. Fine thanks. I‘m having fun with Redis
3. I should look into this NOSQL thing ASAP
注意LRANGE 带有两个索引,一定范围的第一个和最后一个元素。这两个索引都可以为负来告知Redis从尾部开始计数,因此-1表示最后一个元素,-2表示list中的倒数第二个元素,以此类推。
As you can guess from the example above, lists can be used, for instance, in order to implement a chat system. Another use is as queues in order to route messages between different processes. But the key point is that you can use Redis lists every time you require to access data in the same order they are added. This will not require any SQL ORDER BY operation, will be very fast, and will scale to millions of elements even with a toy Linux box.
正如你可以从上面的例子中猜到的,list可被用来实现聊天系统。还可以作为不同进程间传递消息的队列。关键是,你可以每次都以原先添加的顺序访问数据。这不需要任何SQL ORDER BY 操作,将会非常快,也会很容易扩展到百万级别元素的规模。
例如在评级系统中,比如社会化新闻网站 reddit.com,你可以把每个新提交的链接添加到一个list,用LRANGE可简单的对结果分页。
在博客引擎实现中,你可为每篇日志设置一个list,在该list中推入进博客评论,等等。 向Redis list压入ID而不是实际的数据
在上面的例子里 ,我们将“对象”(此例中是简单消息)直接压入Redis list,但通常不应这么做,由于对象可能被多次引用:例如在一个list中维护其时间顺序,在一个集合中保存它的类别,只要有必要,它还会出现在其他list中,等等。
让我们回到reddit.com的例子,将用户提交的链接(新闻)添加到list中,有更可靠的方法如下所示:
$ redis-cli incr next.news.id
(integer) 1
$ redis-cli set news:1:title "Redis is simple"
OK
$ redis-cli set news:1:url "http://code.google.com/p/redis"
4. 2
而有些看上去并不简单的操作仍然能使用相应的Redis命令轻松实现。例如我们也许想获得一份同时拥有标签1, 2, 10和27的对象列表。这可以用SINTER命令来做,他可以在不同集合之间取出交集。因此为达目的我们只需:
$ redis-cli sinter tag:1:objects tag:2:objects tag:10:objects tag:27:objects
... no result in our dataset composed of just one object ...
在命令参考文档中可以找到和集合相关的其他命令,令人感兴趣的一抓一大把。一定要留意SORT命令,Redis集合和list都是可排序的。 题外话:如何为字符串获取唯一标识
在标签的例子里,我们用到了标签ID,却没有提到ID从何而来。基本上你得为每个加入系统的标签分配一个唯一标识。你也希望在多个客户端同时试着添加同样的标签时不要出现竞争的情况。此外,如果标签已存在,你希望返回他的ID,否则创建一个新的唯一标识并将其与此标签关联。
Redis 1.4将增加Hash类型。有了它,字符串和唯一ID关联的事儿将不值一提,但如今我们如何用现有Redis命令可靠的解决它呢?
我们首先的尝试(以失败告终)可能如下。假设我们想为标签“redis”获取一个唯一ID: