Redis

Redis

简介

redis是一种高级的key:value存储系统,其中value支持五种数据类型:

  1. 字符串(String)
  1. 字符串列表(Lists)
  2. 字符串集合(Sets)
  3. 有序字符串集合(Sorted Sets)
  4. 哈希(Hashes)

Key不要太长,尽量不超过1024字节,不仅消耗内存,而且会降低查找效率;

Key也不要太短,太短的话,会降低可读性

在一个项目中,key最好使用统一的命名格式。uid:111:pwd:abc

String

String是一个很基础的数据类型,也是任何存储系统都必备的数据类型。

set mystr "hello world"
get mystr

字符串类型的用法,非常简单,因为二进制安全的,所以可以把一个图片文件的内容作为字符串来存储。

另外,还可以通过字符串类型进行数值操作:

set mynum "2"
get mynum
incr mynum
get mynum  
"3"

在数值操作时,redis会将字符串类型转换为数值。

由于INCR等指令本身就具有原子操作的特性,所以完全可以利用redis的incr、incrby、decr、decrby等指令来实现原子计数的效果。

假设某个场景下,有3个客户端同时读取mynum的值,并且給其+1,那么最后mynum的值一定是5。很多网站用redis来进行业务上的统计技术需求。

其他命令:
SETNX :SET if not exists(如果不存在,则SET), Setnx可以用作加锁原语。

比如说,要对关键字(key)foo加锁,可以尝试一下方式:

setnx lock.foo <current Unix time + lock timeout +1>

可以通过del lock.foo来释放锁。

处理死锁:如果因为客户端失败、崩溃或其他原因没有释放锁的话,怎么办? 这种状况可以通过检测发现,因为上锁的key保存的是Unix时间戳,加入key值的时间戳小于当前时间戳,表示锁已经不再生效。
如果有多个客户端同时竞争的时候,就不能通过删除锁来进行解决了。

C1和C2读取lock.foo并检查时间戳,setnx都返回0,因为他已经被C3锁上了,但C3在上锁后就崩溃了。

  1. C1向lock.foo发送Del命令。
  2. C1向lock.foo发送setnx命令并成功。
  3. C2向lock.foo发送Del命令。
  4. C2向lock.foo发送setnx命令并成功。
  5. C1和C2都获得了锁。
    但是以下算法可以避免以上的问题。
    1.C4向lock.foo发送setnx命令。
    2.因为C3崩溃,还锁着lock.foo,所以redis向C4返回0.
    3.C4向lock.foo发送GET命令,查看lock.foo的锁是否过期。如果不,休眠,重试。
    4.如果lock.foo内的unix时间戳比当前时间戳老,则C4执行一下命令:
GETSET lock.foo <current Unix timestamp + lock timeout + 1>

因为getset的作用,C4可以查看GETSET的返回值,确定lock.foo之前存储的旧值仍是哪个过期的时间戳,如果是的话,那么C4获得锁。

SETEX : 将值value关联到key,并将key的生存时间设为seconds(以秒为单位)。如果key已经存在,setex命令将会覆写旧值。
这个命令类似于一下的两个命令:

set key value
expire key seconds

setex 是一个原子性的操作,关联值和设置生存时间两个动作会在同一时间内完成,该命令在redis用作缓存的时候,非常实用。

Mset 同时设置一个或者多个key-value对。当发现同名的key存在时,mset会用新值覆盖旧值,如果不希望覆盖同名的key,请使用msetnx

MsetNx 类似于setnx,不做赘述。

Append 如果key存在,并且是一个字符串,append会将value追加到key原来的值之后。如果不存在,则append就简单的将给定的key设为value,就像执行set key value一样。

Mget 返回所有(一个或者多个)给定的key值。

GetRange: getrange key start end.返回key中字符串值的子字符串,字符串截取的范围由start和end两个偏移量决定。负数表示从最后开始计数。

GetSet: getset key value
将给定的key值设为value,并且返回key的旧值。

getset可以和incr组合使用,实现一个有原子性复位操作的计数器。
举例来说,每当某个时间发生时,进程可能对一个名为 mycount的key调用incr操作,通常我们还要在一个原子时间内完成获得计数器的值和将计数器复位为0两个操作。
可以用命令 getset mycounter 0来实现这一目标。

incr mycount
(integer) 11
getset mycount 0
"11"
get mycount
"0"

Decr decr key.将key中存储的数字值减一。
Decrby decrby key decrement
将key所存储的值减去减量decrement。如果key不存在,以0为初始值,然后执行decrby操作。

Incr incr by 将key中存储的数字值加一
Incrby incrby key increment 将key所存储的值加上增量increment

Lists

redis的另外一个重要的数据结构是lists(列表)。

redis的lists底层实现不是数组,而是链表。也就是说无论是10个元素的链表,还是1百万个元素的链表,从头尾插入一个元素的时间复杂度是常数级别的,也就是Lpush|Rpush插入新元素的时间是相同的。

缺点为:定位某个元素的速度很慢。

常用的操作包括: Lpsuh,Rpush,Lrange,Lpop

lpush mylist "1"
(integer)1
rpush mylist "2"
(integer)2
lpush mylist "0"
(integer)3
lrange mylist 0 1
1) "0"
2) "1"
lrange mylist 0 -1
1) "0"
2) "1"
3) "2"

Lists的应用场景非常广泛:
1.可以利用lists来实现消息队列,而且可以确保先后顺序。
2.利用Lrange可以方便实现分页的功能
3.在Blog中,每篇Blog的评论可以存入一个单独的list中。

lpush 将一个或多个值插入到列表表头

lpushx 将value插入列表key的表头,当且仅当key存在并且是一个列表

lpop lpop key,移除并返回列表key的头元素。

rpop rpop key,移除并返回列表key的尾元素。

blpop 是列表的阻塞式(blocking)弹出原语。如果阻塞,也就是给定的所有key都不存在或者包含空列表,那么blpop命令将阻塞连接,直到等待超时,或另一个客户端对给定的key执行lpush或rpush为止。超时参数timeout接受一个以秒为单位的数字作为值。超时参数设为0表示阻塞时间可以无限期延长。

相同的key可以被多个客户端同时阻塞,不同的客户端放进一个队列里,按先阻塞先服务的顺序为key进行blpop命令。
Blpop可以用在pipeline(批量的发送多个命令并读入多个回复)[不是很理解]

llen 返回key的长度

lrange 返回列表key中指定区间内的元素。

lset lset key index value 将列表key下标为index的元素的值改为value

ltrim ltrim key start stop 对一个列表进行修剪,让列表只保留指定区间内的元素,不在指定区间内的元素都将被删除。

lindex lindex key index 返回列表key中,下标为index的元素。

linsert linsert key before | after pivot value,将value插入到列表key当中,位于值pivot之后,当pivot不存在于列表key时,不执行任何操作。当key不存在时,key被视为空列表,不执行任何操作。如果key不是列表类型,返回一个错误。

rpoplpush rpoplpush source destination 一个原子时间内执行两个操作。将列表source中的最后一个元素弹出,返回客户端,将source弹出的元素插入到列表destination,作为destination列表的头元素

一个安全的队列。redis经常被用作队列,用户在不同程序之间有效的交换信息。一个程序(producer)通过lpush命令将消息放入队列,而另一个程序(consumer)通过rpop取出队列中等待时间最长的消息。
不幸的是,在这个过程中,一个消费者可能在获取一个消息之后崩溃,而未执行完成的消息也会因此丢失。
使用rpoplpush命令可以解决这个问题,因为它在返回一个消息之余,还将该消息添加到另一个列表中,另外的这个列表可以用作消息的备份表:如果一起正常,当消费者完成该消息的处理之后,可以用lrem命令将该罅隙从备份表中删除。
另一方面,助手程序可以通过监视备份表,将超过一定处理时限的消息重新放入队列中去(负责处理该消息的消费者可能已经崩溃),这样就不会丢失任何消息了。

BRPOPLPUSH brpoplpush source destination timeout 是上一个命令的阻塞版本。

SETS

redis中的集合,是一种无序的集合,集合中的元素没有先后顺序

集合相关的操作也很丰富,如添加新元素、删除已有元素、取交集、取并集、取差集。

对于集合的使用,也有一些常见的场景。如QQ的好友标签,就是把每一个用户的标签储存在一个集合之中。

SADD sadd key member 将一个或者多个member元素加入到集合key中,已经存在集合的member元素将被忽略。

SREM srem key member 移除集中key中的一个或多个member元素,不存在的member元素会被忽略。

smembers smembers key 返回集合key中的所有成员。

sismember 判断member元素是否是key的成员。

scard scard key 返回集合key的基数

smove smove source destination member
将member元素从source集合移动到destination集合。
如果source集合不存在或不包含指定的member元素,则smove命令不执行任何操作,仅返回0.否则,member元素从source集合中被移除,并添加到destination集合中去。
当destination集合已经包含member元素时,smove命令只是简单地将source集合中的member元素删除。

Spop spop key 移除并返回集合中的一个随机元素。
返回被移除的随机元素,当key不存在或key是空集时,返回nil

srandmember srandmember key 返回集合中的一个随机元素

sinter sinter key 返回一个集合的全部成员,该集合是所有给定集合的交集

sinterstore sinterstore destination key 它与sinter相同,但它将结果保存到destination集合,而不是简单地返回结果集。如果destination可以是key本身。

sunion 返回一个集合的全部成员,该集合时所有给定集合的并集。

sunionstore sunionstore destination key 此命令等同于sunion,但它将保存到destination集合,而不是简单地返回结果集。
如果destination已经存在,则将其覆盖。destination可以是key本身。

sdiff sdiff key 返回一个集合的全部成员,该集合是所有给定集合的差集。

sdiffstore 此命令等同于sdiff,但它将结果保存到destination集合中,而不是简单地返回结果集。

有序集合

redis不仅提供了无序集合(sets), 还提供了有序集合(sorted sets)。有序集合中的每个元素都关联一个序号(score),这便是排序的一句。

将redis中的有序集合称为zsets,这是因为有序集合相关的操作指令都是以z开头的,比如zrange、zadd、zrevrange、zrangebyscore等

Zadd将一个zadd key score member 将一个或多个member元素机器score值加入到有序集key当中

Zrem 移除有序集key中的一个或多个成员,不存在的成员将被忽略。

Zcard 返回有序集key的基数

Zcount 返回有序集key中,score值在min和max之间的成员

Zscore 返回有序集key中,成员member的score值

Zincrby 为有序集key的成员member的score值加上增量increment。

Zrange 返回有序集key中,指定区间内的成员,按score值递增排序

Zrevrange 返回有序集中,指定区间内的成员。其中成员的位置按score值递减来排列。具有相同score值的成员按字典序反序排列

Zrangebyscore 返回有序集key中,所有score值介于min和max之间的成员。有序集成员按score值递增次序排列

Zrank 返回有序集key中成员member的排名。其中有序集成员按score值递增顺序排列

Zrevrank 返回有序集key中成员member的排名。其中有序集成员按score值递减排序。

Zremrangebyrank 移除有序集key中,指定排名区间内所有成员。

Zinterstore 计算给定的一个或多个有序集的交集,其中给定key的数量必须以numkeys参数指定,并将该交集存储到destination。

Zunionstore 计算给定的一个或多个有序集的并集,其中给定key的数量必须以numkeys参数指定,并将该并集存储到destination

Hash

hash存的是字符串和字符串之间的映射,比如一个用户要存储其全名、姓氏、年龄等等,就很适合用哈西。

Hset 将哈希表key中的域field的值设为value

Hsetnx 将哈希表key中的域field的值设为value,当且仅当域field不存在

Hmset 同时将多个field-value对设置到哈希表key中

Hget 返回哈希表key中给定域field的值

Hmget 返回哈希表key中给定的一个或多个域的值

Hgetall 返回哈希表中,所有的域和值

Hdel 删除哈希表key中一个或多个域,不存在的域将被忽略

Hlen 返回哈希表key中域的数量

Hexists 查看哈希表key中,给定域field是否存在

Hincrby 为哈希表key中的域field的值加上增量increment

Hkeys 返回哈希表key中的所有域

Hvals 返回哈希表key中的所有值

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容