redis是一个key-value型的非关系型数据库,key为String类型,区分大小写,value支持5种数据类型
关于redis的命令操作,可参考http://doc.redisfans.com/官方文档,非常全且细。
建议先了解RedisObject
string 是 redis 最基本的类型,也是二进制安全的
常用命令:
/**
* ex: 设置秒级过期时间
* px:设置毫秒级过期时间
* nx: 仅当键不存在时才能设置成功,set key value nx 也可写作 setnx key value
* xx:仅当键存在时才能设置成功
*/
set key value [ex seconds] [px milliseconds] [nx|xx]
/** 取值 */
get key
/** 批量取值 */
mget key1 [key2 ...]
/** 批量赋值 */
mset key value [key value ...]
/** 对string类型的value进行自增或自减,该string类型的值必须是整数形式 */
incr/decr key
/** 对指定key增加num */
incrby/decrby key num
注意事项:
1. 对string类型的操作,部分操作其返回值为“ok”表示成功,nil表示null,有时integer类型0或1表示失败或成功。有时integer类型则表示运行结果值,如strlen则返回的是字符串长度
2. set与mset的选择,指令的完成时间包含2次传输时间以及执行时间。同时还要考虑redis的单线程单条语句的执行时间,不能严重阻塞。
3. setex设置key的生命周期,但是会被后续命令覆盖,比如setex key value 10设为10秒,10s内再次执行set key value2 那么前一个过期时间就不再生效了,该key不会过期
应用场景:
1.1 生成自增 id
当 redis 的 string 类型的值为整数形式时,redis 可以把它当做是整数一样进行自增(incr)自减(decr)操作。由于 redis 所有的操作都是原子性的,所以不必担心多客户端连接时可能出现的事务
问题。
实际上type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw 长字符(>39)或者是embstr 短字符(<=39字节)或者是int 长整型,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如"20"这样的字符串,当遇到incr、decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。如果你试图对raw编码的值进行incr操作则报错
1.2 计数 (点赞,视频播放量,每播放一次就+1)
long incrVideoCounter(long id) {
key = "video:playCount:" + id;
return redis.incr(key);
}
1.3 接口防刷 (验证码登录,公司一般的验证码等发短信功能都是调用的第三方接口,如果被有心之人利用了,会给公司造成一定的损失,所以简单的解决方法就是限流)
附: ttl 命令可返回 key 的剩余过期时间,单位为秒。-1表示永不过期
phoneNum = "138xxxxxxxx";
key = "shortMsg:limit:" + phoneNum;
// SET key value EX 60 NX
isExists = redis.set(key,1,"EX 60","NX");
if (isExists != null || redis.incr(key) <=5) {
// 通过
} else {
// 限速
}
Redis hash是一个键值对集合,是一个string类型的field和value的映射表,hash特别适合用于存储对象。
命令 | 描述 | 用法 |
HSET | (1)将哈希表Key中的域field的值设为value (2)key不存在,一个新的Hash表被创建 (3)field已经存在,旧的值被覆盖 |
HSET key field value |
HGET | (1)返回哈希表key中给定域field的值 | HGET key field |
HDEL | (1)删除哈希表key中的一个或多个指定域 (2)不存在的域将被忽略 |
HDEL key filed [field ...] |
HEXISTS | (1)查看哈希表key中,给定域field是否存在,存在返回1,不存在返回0 | HEXISTS key field |
HGETALL | (1)返回哈希表key中,所有的域和值 | HGETALL key |
HINCRBY | (1)为哈希表key中的域field加上增量increment (2)其余同INCR命令 |
HINCRYBY key filed increment |
HKEYS | (1)返回哈希表key中的所有域 | HKEYS key |
HLEN | (1)返回哈希表key中域的数量 | HLEN key |
HMGET | (1)返回哈希表key中,一个或多个给定域的值 (2)如果给定的域不存在于哈希表,那么返回一个nil值 |
HMGET key field [field ...] |
HMSET | (1)同时将多个field-value对设置到哈希表key中 (2)会覆盖哈希表中已存在的域 (3)key不存在,那么一个空哈希表会被创建并执行HMSET操作 |
HMSET key field value [field value ...] |
HVALS | (1)返回哈希表key中所有域对应的值 | HVALS key |
列表有两个特点:1. 有序 2. 可以重复
命令 | 描述 | 用法 |
LPUSH | (1)将一个或多个值value插入到列表key的表头 (2)如果有多个value值,那么各个value值按从左到右的顺序依次插入表头 (3)key不存在,一个空列表会被创建并执行LPUSH操作 (4)key存在但不是列表类型,返回错误 |
LPUSH key value [value ...] |
LPUSHX | (1)将值value插入到列表key的表头,当且仅当key存在且为一个列表 (2)key不存在时,LPUSHX命令什么都不做 |
LPUSHX key value |
LPOP | (1)移除并返回列表key的头元素,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除 |
LPOP key |
LRANGE | (1)返回列表key中指定区间内的元素,区间以偏移量start和stop指定 (2)start和stop都以0位底 (3)可使用负数下标,-1表示列表最后一个元素,-2表示列表倒数第二个元素,以此类推 (4)start大于列表最大下标,返回空列表 (5)stop大于列表最大下标,stop=列表最大下标 |
LRANGE key start stop |
LREM | (1)根据count的值,移除列表中与value相等的元素 (2)count>0表示从头到尾搜索,移除与value相等的元素,数量为count (3)count<0表示从从尾到头搜索,移除与value相等的元素,数量为count (4)count=0表示移除表中所有与value相等的元素 |
LREM key count value |
LSET | (1)将列表key下标为index的元素值设为value (2)index参数超出范围,或对一个空列表进行LSET时,返回错误 |
LSET key index value |
LINDEX | (1)返回列表key中,下标为index的元素 |
LINDEX key index |
LINSERT | (1)将值value插入列表key中,位于pivot前面或者后面 (2)pivot不存在于列表key时,不执行任何操作 (3)key不存在,不执行任何操作 |
LINSERT key BEFORE|AFTER pivot value |
LLEN | (1)返回列表key的长度 (2)key不存在,返回0 |
LLEN key |
LTRIM | (1)对一个列表进行修剪,让列表只返回指定区间内的元素,不存在指定区间内的都将被移除 | LTRIM key start stop |
RPOP | (1)移除并返回列表key的尾元素 | RPOP key |
RPOPLPUSH | 在一个原子时间内,执行两个动作: (1)将列表source中最后一个元素弹出并返回给客户端 (2)将source弹出的元素插入到列表desination,作为destination列表的头元素 |
RPOPLPUSH source destination |
RPUSH | (1)将一个或多个值value插入到列表key的表尾 | RPUSH key value [value ...] |
RPUSHX | (1)将value插入到列表key的表尾,当且仅当key存在并且是一个列表 (2)key不存在,RPUSHX什么都不做 |
RPUSHX key value |
BRPOPLPUSH | (1)RPOPLPUSH的阻塞版本 | BRPOPLPUSH source destination |
BLPOP/BRPOP | (1) 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。(2)可以监听多个列表,如果所有列表都没有元素则阻塞,如果其中一个有元素则从该列表中弹出该元素(会按照key的顺序进行读取,可以实现具有优先级的队列)(2)如果列表为空,返回一个 nil 。 否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。 | BRPOP KEY1 [KEY2...] TIMEOUT |
栈,先进后出 lpush+lpop;队列,先进先出 lpush+rpop
注意左右的理解,个人理解方式可以不同,lpush我理解为元素从左边开始放,后续元素将前面的元素从左向右边推,有的人理解为每个元素放在之前元素的左侧,这两种方式都可以。lrange的顺序始终是从左至右的,所以跟lpush相反,先进的排在最后。
从元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将会是非常高效的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完成。然而需要说明的是,如果元素插入或删除操作是作用于链表中间,那将会是非常低效的。
Redis链表经常会被用于消息队列的服务,以完成多程序之间的消息交换。假设一个应用程序正在执行LPUSH操作向链表中添加新的元素,我们通常将这样的程序称之为"生产者(Producer)",而另外一个应用程序正在执行RPOP操作从链表中取出元素,我们称这样的程序为"消费者(Consumer)"。如果此时,消费者程序在取出消息元素后立刻崩溃,由于该消息已经被取出且没有被正常处理,那么我们就可以认为该消息已经丢失,由此可能会导致业务数据丢失,或业务状态的不一致等现象的发生。然而通过使用RPOPLPUSH命令,消费者程序在从主消息队列中取出消息之后再将其插入到备份队列中,直到消费者程序完成正常的处理逻辑后再将该消息从备份队列中删除。同时我们还可以提供一个守护进程,当发现备份队列中的消息过期时,可以重新将其再放回到主消息队列中,以便其它的消费者程序继续处理。另外,为了避免不停的调用rpop方法查看List中是否有待处理消息,每调用一次都会发起一次连接,这会造成不必要的浪费。我们可以使用这些命令的阻塞式版本。关于队列的更多细节,计划另写一篇博客学习一下,这里不再赘述。
Redis的set是string类型的无序集合。其实现其实是利用了hash中的键。无序且不可重复
命令 | 描述 | 用法 |
SADD | (1)将一个或多个member元素加入到key中,已存在在集合的member将被忽略 (2)假如key不存在,则只创建一个只包含member元素做成员的集合 (3)当key不是集合类型时,将返回一个错误 |
SADD key number [member ...] |
SCARD | (1)返回key对应的集合中的元素数量 | SCARD key |
SDIFF | (1)返回一个集合的全部成员,该集合是第一个Key对应的集合和后面key对应的集合的差集 | SDIFF key [key ...] |
SDIFFSTORE | (1)和SDIFF类似,但结果保存到destination集合而不是简单返回结果集 (2) destination如果已存在,则覆盖 |
SDIFFSTORE destionation key [key ...] |
SINTER | (1)返回一个集合的全部成员,该集合是所有给定集合的交集 (2)不存在的key被视为空集 |
SINTER key [key ...] |
SINTERSTORE | (1)和SINTER类似,但结果保存在destination集合而不是简单返回结果集 (2)如果destination已存在,则覆盖 (3)destination可以是key本身 |
SINTERSTORE destination key [key ...] |
SISMEMBER | (1)判断member元素是否key的成员,0表示不是,1表示是 | SISMEMBER key member |
SMEMBERS | (1)返回集合key中的所有成员 (2)不存在的key被视为空集 |
SMEMBERS key |
SMOVE | (1)原子性地将member元素从source集合移动到destination集合 (2)source集合中不包含member元素,SMOVE命令不执行任何操作,仅返回0 (3)destination中已包含member元素,SMOVE命令只是简单做source集合的member元素移除 |
SMOVE source desination member |
SPOP | (1)移除并返回集合中的一个随机元素,如果count不指定那么随机返回一个随机元素 (2)count为正数且小于集合元素数量,那么返回一个count个元素的数组且数组中的元素各不相同 (3)count为正数且大于等于集合元素数量,那么返回整个集合 (4)count为负数那么命令返回一个数组,数组中的元素可能重复多次,数量为count的绝对值 |
SPOP key [count] |
SRANDMEMBER | (1)如果count不指定,那么返回集合中的一个随机元素 (2)count同上 |
SRANDMEMBER key [count] |
SREM | (1)移除集合key中的一个或多个member元素,不存在的member将被忽略 | SREM key member [member ...] |
SUNION | (1)返回一个集合的全部成员,该集合是所有给定集合的并集 (2)不存在的key被视为空集 |
SUNION key [key ...] |
SUNIONSTORE | (1)类似SUNION,但结果保存到destination集合而不是简单返回结果集 (2)destination已存在,覆盖旧值 (3)destination可以是key本身 |
SUNION destination key [key ...] |
set类型在功能上还存在着一个非常重要的特性,即在服务器端完成多个Sets之间的聚合计算操作,交集并集差集,如unions、interstore和difff。由于这些操作均在服务端完成,因此效率极高,而且也节省了大量的网络IO开销。
应用范围:
1). 可以使用Redis的Set数据类型跟踪一些唯一性数据,比如访问某一博客的唯一IP地址信息。对于此场景,我们仅需在每次访问该博客时将访问者的IP存入Redis中,Set数据类型会自动保证IP地址的唯一性。
2). 充分利用Set类型的服务端聚合操作方便、高效的特性,可以用于维护数据对象之间的关联关系。比如所有购买某一电子设备的客户ID被存储在一个指定的Set中,而购买另外一种电子产品的客户ID被存储在另外一个Set中,如果此时我们想获取有哪些客户同时购买了这两种商品时,Set的sinterstore命令就可以充分发挥它的方便和效率的优势了。
有序不可重复
命令 | 描述 | 用法 |
ZADD | (1)将一个或多个member元素及其score值加入有序集key中 (2)如果member已经是有序集的成员,那么更新member对应的score并重新插入member保证member在正确的位置上 (3)score可以是整数值或双精度浮点数 |
ZADD key score member [[score member] [score member] ...] |
ZCARD | (1)返回有序集key的元素个数 | ZCARD key |
ZCOUNT | (1) 返回有序集key中,score值>=min且<=max的成员的数量 | ZCOUNT key min max |
ZRANGE | (1)返回有序集key中指定区间内的成员,成员位置按score从小到大排序 (2)具有相同score值的成员按字典序排列 (3)需要成员按score从大到小排列,使用ZREVRANGE命令 (4)下标参数start和stop都以0为底,也可以用负数,-1表示最后一个成员,-2表示倒数第二个成员 (5)可通过WITHSCORES选项让成员和它的score值一并返回 |
ZRANGE key start stop [WITHSCORES] |
ZRANK | (1)返回有序集key中成员member的排名,有序集成员按score值从小到大排列 (2)排名以0为底,即score最小的成员排名为0 (3)ZREVRANK命令可将成员按score值从大到小排名 |
ZRANK key number |
ZREM | (1)移除有序集key中的一个或多个成员,不存在的成员将被忽略 (2)当key存在但不是有序集时,返回错误 |
ZREM key member [member ...] |
ZREMRANGEBYRANK | (1)移除有序集key中指定排名区间内的所有成员 | ZREMRANGEBYRANK key start stop |
ZREMRANGEBYSCORE | (1)移除有序集key中,所有score值>=min且<=max之间的成员 | ZREMRANGEBYSCORE key min max |
zset底层存储还是基于set结构,因此数据也不能重复,如果重复添加相同数据,score的值将被反复覆盖。
zset的score保存的值也可以是一个双精度的浮点数,基于双精度浮点数的特征,可能会丢失精度。