Redis系列三:redis支持的数据类型
以下是摘自redis官网,描述了redis支持了哪些数据类型:
It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.
以下只介绍常用的前五个。
一、字符串(String)
1、字符串类型
实际上可以是字符串(包括XML、JSON),数字(整型、浮点型),二进制(图片、音频、视频)等,但最大不超过512MB。
2、设置命令
set name zhangsan ex 10 //10秒过期 px 10000 毫秒过期
setnx name zhangsan //不存在键name时才设置,返回1设置成功;若已存在键name则返回0
set age 29 //已存在键age则覆盖之前的键值,返回1成功
场景:通过setnx只有一个能够设置成功,可做分布式锁;也可通过setnx占位,防止连续调用的场景
获值的命令:get age //存在则返回value,不存在键则返回nil
批量设置:mset name zhangsan age 15
批量获取 mget name age //返回zhangsan 15
若没有mget命令,则要执行n次get,从而占用网络资源影响性能
使用mget=1次网络请求redis内部n次查询,一次性返回所有查询结果
3、计数
incr age //无age键则从0自增返回1;若age不死整数则返回错误,为整数则自加1
decr age//整数age自减1,非整数返回错误,无age键从0自减返回-1
incrby age 2//整数自加2,非整数返回错误,无age键从0自加2返回2
decrby age 2//同上
incrbyfloat age 1.1 //整数age+1.1
4、append追加指令
set name zhang;append name san//追加后返回zhangsan
5、字符串长度
set name "你好"; strlen name //返回6,每个中文占3个字节
6、截取字符串
set name zhangsna; getrange name 2 4//返回ang
7、内部编码
int:8字节长整型
set age 100; object encoding age //返回int
embstr:小于等于39字节串
set name zhangsan; object encoding name //返回embstr
raw:大于39字节的字符串
set name iafhsdfsdhfhusdfufdhhdghdbvjdvhdushfuisdhfudsihfusdhfuisgsvbnsdhfsduhfsduhfdsfhudhgfghdf
object encoding name //返回raw
8、切换数据库
select 2//16个数据库 0-15
9、应用场景
键值设计:业务名:对象名:id:[属性]
数据库为order,用户表为user,对应的键可为order:user:1 , order:user:name
注意:
redis目前处于受保护模式,不允许非本地客户端链接,可以通过给redis设置密码,然后客户端链接的时候,写上密码句可以了
127.0.0.1:6379>config set requirepas 123456 临时生效
或修改redis.conf requirepass 123456
启动时: ./redis-server redis.conf指定conf
./redis-cli -p 6379 -a 12345678 //需要加入密码才能访问
二、哈希(hash)
hash时一个string类型的field和value的映射表。hash适用于存储对象。
1、命令
hset key field value
设值:hset user:1 name zhangsan //成功返回1,失败返回0
取值:hget user:1 name//返回zhangsan
删值:hdel user:1 nage //返回删除的个数
计算键对应的字段个数:
hset user:1 name zhangsan; hset user:1 age 15;
hlen user:1 //返回2,user:1有两个属性
批量设值:hmset user:2 name zhangsan age 15 //返回OK
批量取值:hmget user:2 name age//返回两行 zhangsan 15
判断field是否存在 hexists user:2 zhangsan //存在返回1,不存在返回0
获取所有field:hkeys user:2 //返回name age两个field
获取user:2所有value:hvals user:2 //返回zhangsan 15
获取user:2所有field与value :hgetall user:2 //返回 name zhangsan age 15
增加1:
hincrby user:2 age 1//15 + 1
hincrbyfloat user:2 age 2//浮点型加2
2、内部编码
ziplist<压缩列表>和hashtable<哈希表>
当field个数少且没有大的value时,内部编码为ziplist
示例:
hmset user:3 name lisi age 20;object encoding user:3//返回ziplist
当value大于64字节,内部编码由ziplist编程hashtable
示例:
hset user:4 name "王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五王五";
object encoding user:4//返回hashtable
hash类型是稀疏,每个键可以有不同的field,若用redis模拟做关系复杂查询开发困难,维护成本高。
3、三种方案实现用户信息存储
1)原生
set user:1 nage haha;
set user:1 age 60;
优点:简单直观,每个键对应一个值
缺点:键数过多,占用内存多,用户信息过于分散,不用于生产环境
2)将对象序列化存入redis
set user:1 serialize(user)
优点:编程简单,内存使用率高
缺点:序列化与反序列化有一定开销,更新属性需要把user全部取出来进行反序列化,更新后再序列化存入redis
3)使用hash类型
hmset user:1 name hahs age 60
优点:简单直观,可减少内存空间消耗
缺点:要控制ziplist与hashtable两种编码转换,且hashtable会消耗更多内存
总结:对于更新不多的情况下,可以使用序列化,对于value值不大于64字节可以使用hash类型
三、列表(list)
1、用来存储多个有序的字符串,一个列表最多可存2的32 次方减1个元素
因为有序,可以通过所以下标获取元素或某个范围内元素列表,列表元素可以重复
2、列表相关命令
添加命令:rpush lpush linsert
rpush name a b c d //从右向左插入a b c d,所以a是最先插入的
lrange name 0 -1//从左到右获取列表所有元素a b c d
lpush fav a b c d //从左向右插入a b c d
lrange fav 0 -1//从左到右获取列表所有元素 d c b a
linsert fav before b r //在b之前插入r,after为之后,使用lrange fav 0 -1 返回d c r b a
查找命令:lrange index llen
lrange key start end //索引下标特点:从左到右为0 到n-1, 若是从右到左则最右边第一个下标为-1,第二个为-2.。。
lindex fav -1 //返回最右末尾a, -2 返回b
llen fav //返回当前列表长度5
删除命令:lpop rpop lrem ltrim
lpop fav //把最左边的第一个元素d删除
rpop fav //把最右边的元素a删除
lrem key count value //删除指定元素,count为0表示删除所有值为value的,count小于0表示从右往左删除count个值为value的
示例:
lpush test b b b b b j x z//键test放入z x j b b b b b
lrange test 0 -1 //查询结果为z x j b b b b b
lrem test 4 b //从左边开始删除b的元素,删除4个
//lrem test 8 b //删除8个b,但只有5个则全部删除
lrange test 0 -1 //删除后的结果为b j x z
lrem test 0 b //检索所有b全部删除j x z
lpush user b b b b b j x z //键user从左到右放入z x j b b b b b
ltrim user 1 3//只保留从第2到第4的元素x j b,其他全部删除
lrange user 0 -1 //查询结果为x j b,其他已全部删除
修改命令:lset
lpush user1 z y x//键user1从左到右翻入x y z
lset user1 2 java//把第3个元素z替换成java
lrange user1 0 -1//查询结果为x y java
阻塞命令:blpop brpop
3、列表内部编码
1)当元素个数少且没大元素,编码为ziplist,减少内存的使用
rpush list a b c
object encoding list//返回ziplist
2)当元素超过512个,或元素超过64字节,内部编码变成linkedlist链表
rpush list a1 a2.............a513或rpush list nnnnnnnnnnnnn.....nnn
object encoding list //linkedlist
在3.2版本亿欧,redis提供了quicklist内部编码,它结合了ziplist和linkedlist两者的优势,之前的ziplist是存在bug的,使用qulicklist内部编码效率更高,所以现在3.2以后看不到这两个编码了,只看到qulicklist。
四、无序集合set
保存多元素,与列表不一样的是不允许有重复元素,且集合是无序的,一个集合最多可存2得32次方减1个元素,除了支持增删改查,还支持集合交集、并集、差集;
1、元素集合set相关命令
元素操作:exists sadd smembers srem scard spop
exists user //检查user键值是否存在
sadd user a b c//向user插入3个元素,返回3
sadd user a b //若再插入吸管弄太难过元素,则重复无效,返回0
srem user a//返回1,删除a元素
scard user //返回2,计算元素个数
sismember user a//判断元素是否在集合存在,存在返回1,不存在返回0
srandmember user a//随机返回2个元素,2位元素个数
spop user 2//随机返回2个元素a b,并将a b从集合中删除
smembers user//此时已没有a b,只有c
集合交集:sinter
add user:1 lili 22 girl
add user:2 zhangsan 22 boy
sinter user:1 user:2 //求两个集合交集,此时返回22
sadd user:3 lucy 22 girl //新增第三个元素
sinter user:1 user:2 user:3 //求三个集合交集,此时返回22
集合的并集(去重):sunion
sunion user:1 user:2 user:3 //三个集合合并,去重,返回 lili zhangsan lucy girl boy
集合差集:sdiff
sdiff user:1 user:2 //lili girl
将集合的结果另存到队列:sinterstore sunionstore sdiffstore
sinterstore user_jj user:1 user:2 //将交集结果保存到user_jj
sunionstore user_bj user:1 user:2 //将并集结果保存到user_bj
sdiffstore user_cj user:1 user:2 //将差集结果保存到user_cj
smembers user_cj //返回lili girl
2、内部编码
sadd user 1 2 3 4 //当元素个数少(小于512个)且都为整数,redis使用intset减少内存的使用
sadd user 1 2....513 //当元素个数超过512个或不为整数(如a b)时,编码为hashtable
object encoding user //hashtables
3、无序集合set的应用场景
标签、社交、查询有共同兴趣爱好的人,智能推荐
使用方式:
给用户添加标签:
sadd user:1:fav basketball football
add user:2 pq
或者给标签添加用户:
sadd basketball:users user:1 user:2
sadd football:users user:1 user:2 user:3
...
计算出共同兴趣爱好的人:
sinter user:1:fav user:2:fav
五、有序集合
常用于排行榜,如视频网站需要对用户上传视频做排行榜,或点赞数
与集合有联系,不能有重复的成员
有序集合与集合set以及队列list的区别:
1、有序集合的相关命令
添加命令
zadd key score member [score member....]
zadd user:zan 200 zhangsan //zhangsan点赞数1,返回操作成功的条数1
zadd user:zan 200 zhangsan 120 lisi 100 wangwu //返回3
zadd test:1 nx 100 zhangsan //键test:1不存在,主要用于添加
zadd test:1 xx incr 200 zhangsan//键test:1必须存在,主要用于修改,此时为300
zadd test:1 xx ch incr -299 zhangsan //返回操作结果1,300-299=1
查看命令
zrange test:1 0 -1 withiscores //查看点赞(分数)与成员名
zcard test:1 //计算成员个数,返回1
查看赞数
zadd test:2 nx 100 zahngsan //新增一个集合
zscore test:2 zhangsan//查看lisi的点赞数(分数),返回100
排名:
zadd user:3 200 zhangsan 120 lisi 100 wangwu //先插入数据
zrange user:3 0 -1 withscores //查看分数与成员
zrank user:3 zhangsan //返回名次:第三名返回2 从0开始到2,共3名
zrevrank user:3 zhangsan//返回0 反排序,点赞数越高,排名越靠前
删除命令:
删除成员:
zrem user:3 zhangsan lisi//返回成功删除2个成员,还剩wangwu
增加分数:
zincrby user:3 10 wangwu //成员王五的分数加10
zadd user:3 xx incr 10 wangwu//和上述命令一样
返回指定排名范围的分数与成员
zadd user:4 200zhangsan 120 lisi 100 wangwu //先插入数据
zrange user:4 0 -1 withscores //返回结果wangwu 100 lisi 120 zhangsan 200 (该处空格其实是换行的)
zrevrange user:4 0 -1 withscores //倒序,结果是zhangsan 200 lisi 120 wangwu 100
返回指定分数范围的成员
zrangebyscore user:4 110 300 withscores //返回结果由低到高 lisi 120 zhangsan 200
zrevrangebyscore user:4 300 110 withscores //返回结果由高到低 zhangsan 200 lisi 120
zrangebyscore user:4 (110 +inf withscores//110到无限大,结果为lisi 120 zhangsan 200
zrevrangebyscore user:4 (110 -inf withscores //无限小到110,结果为wangwu 100
返回指定分数范围的成员个数:
zcount user:4 110 300//返回2,由lisi和zhangsan两条数据
删除指定排名内的升序元素:
zremrangebyrank user:4 0 1 //分数升序排序,删除第0个与第1个,只剩zhangsan
删除指定分数范围的成员:
zadd user:5 200 zhangsan 120 lisi 100 wangwu//先插入测试数据
zremrangebyscore user:5 210 300 //删除分数在210与300范围的成员
zremrangebyscore user:5 (100 +inf //删除分数大于100(不包括100),还剩wangwu
有序集合交集:
格式:zinterstore destination numkeys key ... [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
destination:交集产生新的元素存储键名称
numkeys: 要做交集计算的键个数
key :元素键值
weights:每个被选中的键对应值乘weight, 默认为1
初始化数据:
zadd user:7 1 james 2 mike 4 jack 5 kate //初始化user:7数据
zadd user:8 3 james 4 mike 4 lucy 2 lee 6 jim //初始化user:8数据
交集例子:
zinterstore user_jj 2 user:7 user:8 aggregate sum //2代表键合并个数,
//aggregate sum可加也不可加上,因为默认是sum
//结果user_jj:4james(1+3), 6mike(2+4)
zinterstore user_jjmax 2 user:7 user:8 aggregate max 或min
//取交集最大的分数,返回结果 3james 4mike, min取最小
weights:
zinterstore user_jjweight 2 user:7 user:8 weights 8 4 aggregate max
//1,取两个成员相同的交集,user:7->1 james 2 mike; user:8->3 james 4 mike
//2,将user:7->james 1*8=8, user:7->mike 2*8 =16,最后user:7结果 8 james 16 mike;
//3,将user:8-> james 3*4=12, user:8->mike 4*4=16,最后user:8结果12 james 16 mike
//4,最终相乘后的结果,取最大值为 12 james 16mike
//5, zrange user_jjweight 0 -1 withscores 查询结果为 12 james 16mike
总结:将user:7成员值乘8,将user:8成员值乘4,取交集,取最大
有序集合并集(合并去重):
格式:zunionstore destination numkeys key ... [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
destination:交集产生新的元素存储键名称
numkeys: 要做交集计算的键个数
key :元素键值
weights:每个被选中的键对应值乘weight, 默认为1
zunionstore user_jjweight2 2 user:7 user:8 weights 8 4 aggregate max
//与以上zinterstore一样,只是取并集,指令一样
2.有序集合内部编码
1)ziplist
zadd user:9 20 james 30 mike 40 lee
object encoding user:9 //返回ziplist
//当元素个数少(小于128个),元素值小于64字节时,使用ziplist编码,可有效减少内存的使用
2)skiplist
zadd user:10 20 james......
//大于128个元素或元素值大于64字节时为skiplist编码
3.使用场景
排行榜系统,如视频网站需要对用户上传的视频做排行榜
点赞数:zadd user:1:20180106 3 mike //mike获得3个赞
再获一赞:zincrby user:1:20180106 1 mike //在3的基础上加1
用户作弊,将用户从排行榜删掉:zrem user:1:20180106 mike
展示赞数最多的5个用户:zrevrangebyrank user:1:20180106 0 4
查看用户赞数与排名:
zscore user:1:20180106 mike zrank user:1:20180106 mike