<img src="http://www.image.jincou.com/ad4dae3acbc54f07809725290417c1b4" width="550" height="582">

前言

如果问你redis有哪些数据结构,你必定能够一口气说出五种根本数据结构: String(字符串)Hash(哈希)List(列表)Set(汇合)zset(有序汇合)

你或者还晓得它还有三种非凡的数据结构类型:Geospatial、Hyperloglog、Bitmap。

但如果问你在理论我的项目中用了哪些数据结构。你是不是感觉如同大大部分只是用了String的数据结构,就算缓存一个对象,也只是通过JSONObject.toJSONString(object)将它转为String存储。取的时候在把这个json字符串转为对象。

那么既然redis提供了5种根本数据结构,必定都有特定的利用场合。

接下来会针对5种根本数据类型,来演示在理论开发中的利用场景。


一、String(字符串)

1. 简介

String 类型是 Redis 中最根本、最罕用的数据类型,甚至被很多玩家当成 Redis 惟一的数据类型去应用。String 类型在 Redis 中是二进制平安(binary safe)的,这意味着 String 值关怀二进制的字符串,不关怀具体格局,你能够用它存储 json 格局或 JPEG 图片格式的字符串。

2、外部编码

如果存储数字的话,是用int(8字节长整型)类型的编码;如果存储非数字,小于等于39字节的字符串,是embstr编码;大于39个字节,则是raw编码。

无关redis的数据外部编码抽空整顿一篇文章独自写

3、应用场景

(1) 存储一些配置数据

在前后分离式开发中,有些数据尽管存储在数据库,然而更改特地少。比方有个全国地区表。以后端发动申请后,后盾如果每次都从关系型数据库读取,会影响网站整体性能。

咱们能够在第一次拜访的时候,将所有地区信息存储到redis字符串中,再次申请,间接从数据库中读取地区的json字符串,返回给前端。

(2) 缓存对象

将对象转为json存储,比方商品信息,用户信息。

(3) 数据统计

redis整型能够用来记录网站访问量,某个文件的下载量,签到人数、视频访问量等等。(自增自减

(4) 工夫内限度申请次数

比方已登录用户申请短信验证码,验证码在5分钟内无效的场景。
当用户首次申请了短信接口,将用户id存储到redis 曾经发送短信的字符串中,并且设置过期工夫为5分钟。当该用户再次申请短信接口,发现曾经存在该用户发送短信记录,则不再发送短信。

(5) 订单号(全局惟一)

有时候你须要去生成一个全局惟一值的时候能够通过redis生成。要害命令:incrby(原子自增)。

SET order_no 2001 --假如订单号从2001开始,这里vlaue必须是int类型INCRBY order_no 1 --自增1,这个时候返回2002

(6) 分布式session

当咱们用nginx做负载平衡的时候,如果咱们每个从服务器上都各自存储本人的session,那么当切换了服务器后,session信息会因为不共享而会失落,咱们不得不思考第三利用来存储session。

通过咱们用关系型数据库或者Redis等非关系型数据库。关系型数据库存储和读取性能远远无奈跟Redis等非关系型数据库比。

4、常用命令

--增set mykey "test"       --为键设置新值,并笼罩原有值setex mykey 10 "hello" -- 设置指定 Key 的过期工夫为10秒,在存活工夫能够获取valuemset key3 "stephen" key4 "liu" --批量设置键--删del mykey --删除已有键--改incr mykey      --值减少1,若该key不存在,创立key,初始值设为0,减少后后果为1decrby mykey 5  --值缩小5--查 exists mykey   --判断该键是否存在,存在返回 1,否则返回0get mykey      --获取Key对应的valuemget key3 key4 --批量获取键


二、Hash(哈希)

1、简介

Hash的数据结构咱们能够简略了解为java中的 Map<String,Map<String,String>,这种构造就特地适宜存储对象,下面的String的类型的确也能够存储对象,但每次批改对象中的某一个属性,都要拿出整个json字符串在批改这个属性,之后在从新插入,而hash的接口特点让咱们能够只批改该对象的某一个属性。

hash数据类型在存储上述类型的数据时具备比 String 类型更灵便、更快的劣势,具体的说,应用 String 类型存储,必然须要转换和解析 json 格局的字符串,即使不须要转换,在内存开销方面,还是 hash 占优势。

2、外部编码

哈希类型元素个数小于512个,所有值小于64字节的话,应用ziplist编码,否则应用hashtable编码。

4、应用场景

(1) Redisson分布式锁

Redisson在实现分布式锁的时候,外部的用的数据就是hash而不是String。因为Redisson为了实现可重入加锁机制。所以在hash中存入了以后线程ID。

(2) 购物车列表

用户id为key商品id为field商品数量为value,恰好形成了购物车的3个因素,如下图所示。

<img src="http://www.image.jincou.com/98b0d46aa5054c4daed3c11a3325dc09" width="400" height="450">

这里波及的命令如下

hset cart:{用户id} {商品id} 1  # 增加商品hincrby cart:{用户id} {商品id} 1 # 减少数量hlen cart:{用户id} # 获取商品总数hdel cart:{用户id} {商品id} # 删除商品hgetall cart:{用户id} 获取购物车所有商品

阐明:以后仅仅是将商品ID存储到了Redis中,在回显商品具体信息的时候,还须要拿着商品id查问一次数据库。

(3) 缓存对象

hash类型的 (key, field, value) 的构造与对象的(对象id, 属性, 值)的构造类似,也能够用来存储对象。

在介绍String类型的利用场景时有所介绍,String + json也是存储对象的一种形式,那么存储对象时,到底用String + json还是用hash呢?

两种存储形式的比照如下表所示。

string + jsonhash
效率很高
容量
灵活性
序列化简略简单

个别对象用string + json存储,对象中某些频繁变动的属性能够思考抽出来用hash存储

3、常用命令

--增hset key field1 "s"   --若字段field1不存在,创立该键及与其关联的Hash, Hash中,key为field1 ,并设value为s ,若字段field1存在,则笼罩 hmset key field1 "hello" field2 "world" -- 一次性设置多个字段    --删hdel key field1 --删除 key 键中字段名为 field1 的字段del key  -- 删除键    --改 hincrby key field 1 --给field的值加1--查hget key field1 --获取键值为 key,字段为 field1 的值hlen key        --获取key键的字段数量hmget key field1 field2 field3 --一次性获取多个字段hgetall key --返回 key 键的所有field值及value值hkeys key   --获取key 键中所有字段的field值hvals key   --获取 key 键中所有字段的value值


三、List(列表)

1、简介

List类型是依照插入程序排序的字符串链表,一个列表最多能够存储2^32-1个元素。咱们能够简略了解为就相当于java中的LinkesdList

和数据结构中的一般链表一样,咱们能够在其头部(left)和尾部(right)增加新的元素。在插入时,如果该键并不存在,Redis将为该键创立一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。

<img src="http://www.image.jincou.com/ecb51b2337954a1090f9a8e9e312414a" width="650" height="220">

2、外部编码

如果列表的元素个数小于512个,列表每个元素的值都小于64字节(默认),应用ziplist编码,否则应用linkedlist编码。

在Redis 3.2之后就都改用ziplist+链表的混合结构,称之为 quicklist(疾速链表)。

2、应用场景

有人会思考用list数据结构来做一些朋友圈的点赞列表、评论列表、排行榜。也不是不能够但我集体感觉这些性能用set或zset来做会更加适合,上面会具体举例。

(1) 音讯队列

lpop和rpush(或者反过来,lpush和rpop)能实现队列的性能。

但如果是这样你发现redis作为音讯队列是不平安的,它不能反复生产,一旦生产就会被删除,同时做消费者确认ACK也麻烦所以个别在理论开发中个别很少用redis中音讯队列,因为当初曾经有Kafka、NSQ、RabbitMQ等成熟的音讯队列了,它们的性能更加欠缺。

4、常用命令

--增 lpush mykey a b --若key不存在,创立该键及与其关联的List,顺次插入a ,b, 若List类型的key存在,则插入value中rpush mykey a b --在链表尾部先插入b,在插入a(lpush list a b那么读的时候是b,a的程序,而rpush是怎么放怎么读出来--删del mykey       --删除已有键 --改lset mykey 1 e        --从头开始, 将索引为1的元素值,设置为新值 e,若索引越界,则返回错误信息--查lrange mykey 0 -1 --取链表中的全副元素,其中0示意第一个元素,-1示意最初一个元素。lrange mykey 0 2  --从头开始,取索引为0,1,2的元素lpop mykey        --获取头部元素,并且弹出头部元素,出栈


四、set(汇合)

1、简介

Redis 中的 set和Java中的HashSet 有些相似,它外部的键值对是无序的、惟一的。它的外部实现相当于一个非凡的字典,字典中所有的value都是一个值 NULL。当汇合中最初一个元素被移除之后,数据结构被主动删除,内存被回收。

2、编码

如果汇合中的元素都是整数且元素个数小于512个,应用intset编码,否则应用hashtable编码。

利用场景

既然set的汇合的个性是:无序的、惟一的。那么咱们思考在一些惟一的场景下应用它。

(1) 抽奖流动

存储某流动中中奖的用户ID ,因为有去重性能,能够保障同一个用户不会中奖两次。

sadd user 1 2 3 4 5  --把所有员工(名称或编号)放入抽奖箱   srandmember user 1   -- 抽取一个一等奖(员工能够反复参加抽奖)spop user 1   -- 抽取一个一等奖(员工不能够反复参加抽奖)srandmember user 3 --抽取3个二等奖smembers user --查看以后抽奖箱中参所有员工scard user  --查看以后抽奖箱中参加抽奖的人数

(2) 点赞

保障一个用户只能点一个赞。key 能够是某某文章、微信朋友圈的文章id

sadd key userId  --点赞(/珍藏) srem key userId  --勾销点赞(/珍藏)smembers key     -- 获取所有点赞(/珍藏)用户  card key  -- 获取点赞用户数量sismember key userId --判断是否点赞(/珍藏)

(3) 好友人脉

key 能够是 用户id

sadd userId1 1 2 3 4 5 sadd userId2 4 5 6 7 8 --某个user的好友id放入汇合sinter userId1 userId2 --获取独特好友sdiff userId1 userId2 --给user2举荐user1的好友sismember userId1 5sismember userId2 5 --验证某个用户是否同时被user1和user2关注

4、常用命令

--增sadd myset a b c --若key不存在,创立该键及与其关联的set,顺次插入a ,b,c。若key存在,则插入value中,若a 在myset中曾经存在,则插入了 b 和 c 两个新成员。--删spop myset       --尾部的b被移出,事实上b并不是之前插入的第一个或最初一个成员srem myset a d f --若f不存在, 移出 a、d ,并返回2--改smove myset myset2 a --将a从 myset 移到 myset2,--查sismember myset a --判断 a 是否曾经存在,返回值为 1 示意存在。smembers myset    --查看set中的内容scard myset       --获取Set 汇合中元素的数量srandmember myset --随机的返回某一成员


五、zset(有序汇合)

1、简介

Sorted-Sets中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为汇合中的成员进行从小到大的排序。成员是惟一的,然而分数(score)却是能够反复的

2、数据编码

当有序汇合的元素个数小于128个,每个元素的值小于64字节时,应用ziplist编码,否则应用skiplist(跳跃表)编码

3、利用场景

既然是 有序的,不可反复的列表,那么就能够做一些排行榜相干的场景。

1) 排行榜(商品销量,视频评分,用户游戏分数)

  1. 新闻热搜。

4、常用命令

--增zadd key 2 "two" 3 "three" --增加两个分数别离是 2 和 3 的两个成员--删zrem key one two  --删除多个成员变量,返回删除的数量--改zincrby key 2 one --将成员 one 的分数减少 2,并返回该成员更新后的分数(分数扭转后相应它的index也会扭转)--查 zrange key 0 -1 WITHSCORES --返回所有成员和分数,不加WITHSCORES,只返回成员zrange key start stop --依照元素的分值从小到大的程序返回从start 到stop之间的所有元素zscore key three --获取成员 three 的分数zrangebyscore key 1 2 --获取分数满足表达式 1 < score <= 2 的成员zcard key       --获取 myzset 键中成员的数量zcount key 1 2  --获取分数满足表达式 1 <= score <= 2 的成员的数量zrank key member --获取元素的排名,从小到大zrevrank key member --获取元素的排名,从大到小

这篇文章就先写到这里,无关redis的数据外部编码,抽空在独自写一篇文章。


申明: 公众号如需转载该篇文章,那麻烦在文章的头部 申明是转至公众号: 后端元宇宙。尊重作者辛苦劳动果实嘛。同时也能够问自己要该文章markdown原稿和原图片。其它状况一律禁止转载哦!

本文由博客一文多发平台 OpenWrite 公布!