前言
Redis有五种数据类型: String, Hash, List, Set, Zset,下面对对这几种类型作详细的介绍
一. String (相当于Java中的字符串)
1.1简介:
string 是redis最基本的类型,一个key对应一个value
string类型是二进制安全的,意思是redis的string可以包含任何数据。比如jpg图片或者序列化对象。
string 类型是Redis最基本的数据类型,一个键最大能存储512MB
二进制安全是指,在传输数据时,保证二进制数据的信息安全,也就是不被篡改,破译等。如果被攻击,能够及时检测出来。
二进制安全特点:
<1>编码,解码发生在客户端完成,执行效率高
<2>不需要频繁的编解码,不会出现乱码
1.2 String命令:
(命令不用区分大小写)
赋值语法:
[1] Redis set 命令常用于设置key的值,如果key已存储值,set 就是写旧值,且无视类型
set key_name value
[2] 只有在key不存在时设置key的值。 Setnx(SET if Not exists) 命令在指定的key不存在时,为key设置指定的值
setnx key value //(面试问题) 解决分布锁的方案之一
[3] 同时设置一个或多个key-value对
mset key value [key value....]
取值语法:
[4] Redis GET 命令用于获取指定 key 的值,如果key不存在,返回 nil。如果key存储的值不是字符串类型,返回一个错误
get key_name
[5] 用于获取存储在指定 key 中字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)
getrange key start end
比较重要的命令
[6] 自增/自减:
incr key_name # Incr 命令将key中存储的数字增1。如果key不存在,那么key的值先被初始化为0,然后再执行INCR操作
自增:increby key_name 增量值
Increby 命令将key中存储的数字加上指定的增量值
[7] 自减: decr 命令将key中存储的数字减1
decr key_name 或 decrby key_name 减值
[8] 字符串拼接:Append 命令用于为指定的 key 追加至末尾,如果不存在,为其赋值
append key_name value
以下的不是经常使用
[9] 对 key 所存储的字符串值,获取指定偏移量上的位(bit)
getbit key offset
[10] 获取所有(一个或多个)给定 key 的值
mget key1 [key2...]
[11] Getset命令用于设置指定 key 的值,并返回 key 的旧值,当 key 不存在时,返回nil
GETSET语法:getset key_name value
[12] 返回 key 所存储的字符串值的长度
strlen key
[13] 删除语法:
del key_name:删除指定key,如果存在,返回值数字类型
1.3 应用场景
[1] string通常用于保存单个字符串或JSON字符串数据
[2] 因为String是二进制安全的,所以你完全可以把一个图片文件内容作为字符串来存储
[3] 计数器(常规key-value缓存应用,常规计数:微博数,粉丝数)
INCR等指令本身就具有原子操作特性,所以我们完全可以利用redis的INCR,INCRBY,DECR,DECRBY等指令来实现原子计数的效果。假如,在某种场景下有3个客户端同时读取mynum的网站并取值(值为2),然后对其同时进行加1操作,那么,最后mynum的值一定是5。不少网站都利用redis的这个特性来实现业务上统计计数的需求
二.哈希(Hash)相当于Java中的一个bean对象
类似于Java中的一个JavaBean(例如:Users(id,name,age,remark))
1.1简介:
Redis hash 是一个string 类型的field和value的映射表,hash特别适合用于存储对象,Redis中每个hash可以存储2^32 - 1键值对(40多亿)
可以看成具有key和value的MAP容器,该类型非常适合于存储值对象的信息,如: uname,upass,age等。该类型的数据仅占用很少的磁盘空间(相比于JSON)
1.2 Hash命令
[1] 赋值语法
hset key field value//为指定的key,设定field/value对
hmset key field value[field1,value1].....同时将多个 field-value(域-值)对设置到哈希表key中
例如: hmset users uname guo age 20 address “北京市”
[2] 取值语法
hget key field//获取存储在hash中的值,根据field得到value
hmget key field [field1] //获取key所有给定字段的值
hgetall key //返回HASH表中所有的字段和值
hkeys key //获取所有哈希表中的字段
hlen key //获取哈希表中字段的数量
[3] 删除语法
hdel key field1[field2] //删除一个或多个HASH表字段
[4] 其他语法:
hsetnx key field value
只有在字段field不存在时,设置哈希表字段的值
hincrby key field increment
为哈希表key中指定字段的整数值加上增量increment
hincrbyfloat key field increment
为哈希表中指定字段的浮点数值加上增量increment
hexists key field
查看哈希表key中,指定的字段是否存在
1.3应用场景
Hash 的应用场景(存储一个用户信息对象数据)
[1] 常用于存储一个对象
[2] 为什么不用string存储一个对象?
hash 是最接近关系数据库结构的数据类型,可以将数据库一条记录或程序中一个对象转换成 hashmap 存放在redis中。
用户ID 为查找的 key, 存储的 value 为用户对象包含姓名,年龄,生日等信息,如果用普通的用户ID 为查找的 key/value 结构来存储,主要有以下2种存储方式:
第一种方式将用户ID 作为查找 key,把其他信息封装成一个对象以序列化方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题
第二种方法是这个用户信息对象有多少成员就存多少个 key-value 对儿,用用户ID+对应属性名称作为唯一标识取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。
总结:
Redis提供的 Hash 很好解决了这个问题,Redis 的 Hash 实际是内部存储的 Value 为一个 HashMap, 并提供了直接存取这个 Map 成员的接口。
三. list (相当于Java语言中的LinkedList类型)
1.1 简介
Redis列表是简单的字符串列表,按照插入的顺序排序,你可以添加一个元素列表的头部(左边) 或者尾部(右边)一个列表最多可以包含 2^32 - 1个元素(每个列表超过40亿个元素)
1.2 命令
[1] 赋值语法:
lpush key value1 [value2] //将一个或多个值插入到列表头部(从左侧添加)
代码示例:
127.0.0.1:6379> lpush l1 a b c d e
(integer) 5
127.0.0.1:6379> lrange l1 0 -1
1) "e"
2) "d"
3) "c"
4) "b"
5) "a"
rpush key value1 [value2] //将列表中添加一个或多个值(从右侧添加)
代码示例:
127.0.0.1:6379> rpush l2 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lrange l2 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
lpush key value //将一个值插入到已存在的列表头部。如果列表不存在,操作失效
RPUSHX key value //一个值插入已存在的列表尾部(最右边)。如果列表不存在,操作失效
[2] 取值语法:
llen key //获取列表长度
lindex key index //通过索引获取列表中的元素
lrange key start stop //获取列表指定范围内的元素
描述: 返回列表中指定区间内的元素,区间以偏移量START 和 END指定,其中0 表示列表第一个元素,1表示第二个元素,以此类推。也可以使用负数下标,以 -1 表示列表中最后一个元素, -2 表示列表中倒数第二个元素,以此类推。
[3] 删除语法
lpop key 移除并获取列表的第一个元素(从左侧删除)
rpop key 移除列表中最后一个元素,返回值为移除的元素(从右侧移除)
blpop key1[key2] timeout 移出并获取列表中的第一个元素,如果列表中没有元素会阻塞列表直到等待超时或发现可弹出元素为止
(说明:如果指定列表中的 key list1 存在数据则返回第一个元素,否则等待相应的s后返回 nil )
brpop key1[key2] timeout 移出并获取列表中的最后一个元素,如果列表中没有元素会阻塞列表直到等待超时或发现可弹出元素为止
ltrim key start stop 对一个列表进行修剪(trim) , 就是说让列表只保留在暂定区间内的元素,不在指定区间之内的元素将被删除
[4] 修改语法:
lset key index value 通过索引设置列表元素的值
linsert key before|after world value 在列表的元素前或者后插入元素
描述:将值 value 插入到列表 key 当中,位于 world 之前或之后
[5] 高级语法
rpoplpush source destination
移除列表的最后一个元素,并将该元素添加到另一个列表并返回
示例描述:
rpoplpush a1 a2 //a1的最后元素移到a2的左侧
rpoplpush a1 a1 //循环列表,将最后元素移到最左侧
brpoplpush source destination timeout
从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
1.3应用场景
项目常应用于:
1.对数据量大的集合数据删减
列表显示,关注列表,粉丝列表,留言评价等…分页,热点新闻(Top5)等
利用LRANGE 还可以很方便的实现分页的功能,在博客系统中,每片博文的评论存入一个单独的 list 中
2.任务队列
( list 通常来实现一个消息队列,而且可以确保先后顺序,不必像 MySql 那样还需要通过Order By 来进行排序)
任务队列介绍(生产者和消费者模式)
在处理Web客户端发送的命令请求时,某些操作的执行时间可能会比我们预期的更长一些,通过将待执行任务相关信息放入队列里面,并在之后对队列进行处理,用户可以推迟执行那些需要一段时间才能完成的操作,这种将工作交给任务处理器来执行的做法称为任务队列。(task queue)
rpopplush source destination
移除列表的最后一个元素,并将该元素添加到另一个列表并返回
示例描述:
常用案例:订单系统的下单流程,用户系统登录注册短信等
四. Set 类型
1.1 简介
[1] Redis的 Set 是 String 类型的无序集合,集合成员是唯一的,这就意味着集合不会出现重复的数据
[2] Redis中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数为 2^32 -1(每个集合可以存储40多亿个成员),类似于Java中的 Hashtable 集合
[3] redis的集合对象 set 的底层存储结构特别稀奇,底层使用了 intset 和 hashtable 两种数据结构存储的,intset 我们可以理解为数组, hashtable 就是普通的哈希表(key为 set 的值,value 为 null)
[4] intset 内部其实是一个数组(int8_t conentents[] 数组),而且存储时候是有序的,因为在查找数据的时候通过二分查找来实现的。
1.2 命令
[1] 赋值语法:
sadd key member1 [member2] # 向集合添加一个或多个成员
例如: sadd s1 a b c # 向集合s1添加 a,b,c 这三个成员
[2] 取值语法
scard key #获取集合的成员数
例如: scard s1 # 返回 s1 集合中的成员数
smembers key #返回集合中所有成员
例如:smembers s1 #返回s1集合中所有成员
sismember key member # 判断member 元素是否是集合 key 的成员(开发中:验证是否存在判断)
srandomember key [count] # 返回集合中一个或多个随机数
[3] 删除语法:
srem key member1 [member2] # 移除集合中一个或多个成员
spop key [count] # 移除并返回集合的一个随机元素
smove source destination member # 将member 元素从source集合移动到destination
例如: smove s1 s2 a # 将s1中的成员a移动到s2中
[4] 差集语法:
sdiff key1 [key2] # 返回给定所有集合的差集 (左侧)
例如: sdiff s1 s2 # 返回的结果为 s1 - s2 (差集)
sdiffstore destination key1 [key2] #返回给定所有集合差集并存储在destination中
例如: sdiffstore s3 s1 s2 # 把s1 - s2 的结果存在s3中
[5] 交集语法:
sinter key1 [key2] #返回给定所有集合的交集(共有数据)
例如: sinter s1 s2 #返回s1 n s2 的结果
sinterstore destination key1 [key2] #返回给定所有集合的交集并存储在destination中
例如: sinterstore s3 s1 s2 #把s1 n s2的结果存入s3中
[6]并集语法:
sunion key1 [key2] #返回所有给定集合的并集
sunionstore destination key1 [key2] # 所有给定集合的并集存储在destination集合中
1.3 应用场景
常应用于:对两个集合的数据[计算] 进行交集,并集,差集运算
[1].以非常方便的实现如共同关注,共同喜好,二度好友等功能。对上面所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存储到一个新的集合中
[2].利用唯一性,可以在统计访问网站所有独立IP
五. 有序集合(sorted set) ZSet
1.1 简介
[1] Redis有序集合,和集合一样也是string 类型元素的集合,且不允许重复的成员
[2] 不同的是每个元素都会关联一个double 类型的分数。redis 正是通过分数来为集合中的成员从小到大排序
[3]有序集合的成员是唯一的,但分数(score)却可以重复
[4] 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中对打的成员数为 2^32 -1 (每个集合可存储40多亿个成员)
[5]Redis的ZSet是有序,且不重复
(很多时候,我们都将redis中的有序集合叫做zset,这是因为在zset中,有序集合相关的操作都是以z开头的)
1.2 命令
[1] 赋值语法:
zadd key score1 member1 [scorce2 member2] # 向有序集合添加一个或多个成员,或者更新已存在成员的分数
例如: zadd z1 75 Java #向有序集合z1中添加成员Java,并给它赋一个关联的分数75
[2] 取值语法:
zcard key #获取有序集合的成员数
zount key min max #计算在有序集合中指定区间分数的成员数
例如: zcount z1 60 80 # 计算出有序集合中分数在60到80之间的成员个数
zrank key member #返回有序集合中指定成员索引
例如: zrank z1 Java #返回有序集合z1中Java的相关索引(即排名)
zrange key start stop [WITHSCORES] #返回有序集合中指定区间的成员,通过索引,分数从低到高
zrevrange key start stop[WITHSOURCES] #返回有序集中指定区间内的成员,通过索引,分数从高到低
例如: zrevrange z1 0 -1 # 按分数从高到低对有序集合z1进行排序并返回(0到-1表示一整个集合)
[3] 删除语法:
del key # 移除集合
zrem key member [member.....] # 移除有序集合中的一个或多个成员
例如:zrem z1 Java # 移除有序集合z1中的Java成员
zremrangebyrank key start stop # 移除有序集合中给定的排名区间的所有成员(第一名是0)(低到高排序)
例如: zremrangebyrank z1 0 2 #移除有序集合z1中排名前三的成员
zremrangebyscore key start stop #移除有序集合中给定分数区间的所有成员
例如: zremrangebyscore z1 60 80 #移除有序集合z1中分数为60到80之间的成员
1.3 应用场景
常应用于:排行榜
[1].比如 twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。
[2].比如一个存储全班同学成绩的 Sorted Set,其集合 value 可以是同学的学号,而 score 就可以使其考试得分,这样数据插入集合的时候,就已经进行了天然的排序
[3].还可以用Sorted Set 来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择score得倒序来获取任务。让重要的任务优先执行。
总结:
这是Redis常用的五种数据类型。