Redis数据类型的常用命令和应用场景

1. Redis数据类型概述

Redis 常见的数据类型有10 种,其中包括 5 种基本数据类型:Strings(字符串)Lists(列表)Sets(集合)Hashes(散列)Sorted sets(Zset有序集合)。除了基本数据类型外,还有 5 种常用数据类型:BitmapsHyperLogLogGeospatial indexesBitfieldsStreams
除了上述 10 种外,还有一部分扩展的数据类型 :例如 JSONtime seriesProbabilistic

2. 五种基本数据类型

5 种基本数据类型是直接提供给用户使用的,其底层实现主要依赖这 8 种数据结构:简单动态字符串(SDS)、LinkedList(双向链表)、Hash Table(哈希表)、SkipList(跳跃表)、Intset(整数集合)、ZipList(压缩列表)、QuickList(快速列表)。

Redis 3.2 之前,List 底层实现是 LinkedList 或者 ZipList。 Redis 3.2 之后,引入了 LinkedList 和 ZipList 的结合 QuickList,List 的底层实现变为 QuickList。

类型数据结构常用命令应用场景
Strings(字符串)SDSSET、SETNX、GET、MSET、INCR需要存储常规数据的场景、需要计数的场景、分布式锁
Lists(列表)LinkedList/ZipList/QuickListRPUSH、LPUSH、LSET 、LPOP、RPOP、LLEN、LRANGE最新文章、最新动态、消息队列
Hashes(散列)Hash Table、ZipListHSET、HSETNX、HMSET、HGET、HGETALL 、HINCRBY对象数据存储场景:用户信息、商品信息、文章信息、购物车信息。
Sets(集合)ZipList、IntsetSADD 、SMEMBERS、SCARD、SISMEMBER、SINTER需要存放的数据不能重复的:文章点赞、动态点赞等场景
Sorted sets(Zset有序集合)ZipList、SkipListZADD 、ZCARD、ZRANGE、ZREVRANK排行榜

3. 其他五种常用类型

类型底层实现常用命令应用场景发布版本
Bitmaps (位图)StringSETBIT、GETBIT、BITCOUNT、BITOP需要保存状态信息的场景:用户签到情况、活跃用户情况、用户行为统计 布隆过滤器2.2.0
HyperLogLog (基数统计)String HyperLogLog算法PFADD 、PFCOUNT、PFMERGE热门网站每日/每周/每月访问 ip 数统计、热门帖子 uv 统计2.8.9
Geospatial indexes (地理空间)Sorted SetGEOADD、GEOPOS、GEODIST 、GEORADIUS 、GEORADIUSBYMEMBER需要管理使用地理空间数据的场景:附近的人、附近的餐馆3.2.0
Bitfields (位域)StringBITFIELD kkk SET u32 #0 1000 、BITFIELD kkk INCRBY u32 #0 -999游戏记录打怪数量、金币数量3.2.0
Streams (流)日志追加(append-only log)的数据结构XADD 、XACK 、XGROUP 、XREADGROUP 、XDEL实时数据处理、消息队列和发布订阅5.0.0

4. 基本使用

4.1 Strings(字符串)

Strings 是一种二进制安全的数据结构,可以用来存储任何类型的数据比如字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的路径)、序列化后的对象。 Redis 并没有使用 C 的字符串表示,而是自己构建了一种 简单动态字符串(Simple Dynamic String,SDS)。相比于 C 的原生字符串,Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是安全的,不会造成缓冲区溢出。

4.1.1 常用命令
命令介绍命令行使用RedisTemplate使用
SET key value存储指定 key 的值set aaa 123redisTemplate.opsForValue().set(“aaa”, “123”);
SETNX key value只有在 key 不存在时设置 key 的值setnx aaa 456redisTemplate.opsForValue().setIfAbsent(“aaa”, “456”);
GET key获取指定 key 的值get aaaredisTemplate.opsForValue().get(“aaa”);
MSET key1 value1 key2 value2…设置一个或多个指定 key 的值mset aaa 111 bbb 222redisTemplate.opsForValue().multiSet();
MGET key1 key2 …获取一个或多个指定 key 的值mget aaa bbbredisTemplate.opsForValue().multiGet();
STRLEN key返回 key 所储存的字符串值的长度strlen aaaredisTemplate.opsForValue().size(“aaa”);
INCR key将 key 中储存的数字值增 1incr aaaredisTemplate.opsForValue().increment(“aaa”);
DECR key将 key 中储存的数字值减 1decr aaaredisTemplate.opsForValue().decrement(“aaa”);
EXISTS key判断指定 key 是否存在exists aaaredisTemplate.hasKey(“aaa”);
DEL key(通用)删除指定的 keydel aaaredisTemplate.delete(“aaa”);
EXPIRE key seconds(通用)给指定 key 设置过期时间expire aaa 20redisTemplate.expire(“aaa”, 200L, TimeUnit.SECONDS);
4.1.2 应用场景
  • 需要存储常规数据的场景:缓存 session、token、图片地址、序列化后的对象(相比较于 Hash 存储更节省内存)。
  • 需要计数的场景:用户单位时间的请求数(简单限流可以用到)、页面单位时间的访问数。
  • 分布式锁:利用 SETNX key value 命令可以实现一个最简易的分布式锁

4.2 List(列表)

Redis 中的 List 其实就是链表数据结构的实现。许多高级编程语言都内置了链表的实现比如 Java 中的 LinkedList,但是 C 语言并没有实现链表,所以 Redis 实现了自己的链表数据结构。Redis 的 List 的实现为一个 双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。

4.2.1 常用命令
命令介绍命令行使用RedisTemplate使用
RPUSH key value1 value2 …在指定列表的尾部(右边)添加一个或多个元素rpush myList a b credisTemplate.opsForList().rightPushAll(“myList”, “a”, “b”, “c”);
LPUSH key value1 value2 …在指定列表的头部(左边)添加一个或多个元素lpush myList 1 2 3redisTemplate.opsForList().leftPushAll(“myList”, “1”, “2”, “3”);
LSET key index value将指定列表索引 index 位置的值设置为 valuelset myList 2 hhredisTemplate.opsForList().set(“myList”, 2, “hh”);
LPOP key移除并获取指定列表的第一个元素(最左边)lpop myListredisTemplate.opsForList().leftPop(“myList”);
RPOP key移除并获取指定列表的最后一个元素(最右边)rpop myListredisTemplate.opsForList().rightPop(“myList”);
LLEN key获取列表元素数量llen myListredisTemplate.opsForList().size(“myList”);
LRANGE key start end获取列表 start 和 end 之间 的元素lrange myList 0 -1redisTemplate.opsForList().range(“myList”, 0, -1);

在这里插入图片描述

4.2.2 应用场景
  • 信息流展示:最新文章、最新动态。

4.3 Hashes(散列)

Redis 中的 Hash 是一个 String 类型的 field-value(键值对) 的映射表,特别适合用于存储对象,后续操作的时候,可以直接修改这个对象中的某些字段的值。Hash 类似于 JDK1.8 前的 HashMap,内部实现也差不多(数组 + 链表)。不过,Redis 的 Hash 做了更多优化。

4.3.1 常用命令
命令介绍命令行使用RedisTemplate使用
HSET key field value设置指定哈希表中指定字段的值(现在同HMSET)hset myUser name aaa tel 199HashMap<String, String> myUserMap = new HashMap<>(); myUserMap.put(“name”, “aaa”);myUserMap.put(“tel”, “199”);redisTemplate.opsForHash().putAll(“myUser”, myUserMap);
HSETNX key field value只有指定字段不存在时设置指定字段的值hsetnx myUser age 20redisTemplate.opsForHash().putIfAbsent(“myUser”, “age”, 20);
HGET key field获取指定哈希表中指定字段的值hget myUser nameredisTemplate.opsForHash().get(“myUser”, “name”);
HMGET key field1 field2获取指定哈希表中一个或者多个指定字段的值hmget myUser age nameredisTemplate.opsForHash().multiGet(“myUser”, Arrays.asList(“name”, “age”));
HGETALL key获取指定哈希表中所有的键值对hgetall myUserredisTemplate.opsForHash().entries(“myUser”);
HEXISTS key field查看指定哈希表中指定的字段是否存在HEXISTS myUser nameredisTemplate.opsForHash().hasKey(“myUser”,“name”);
HDEL key field1 field2删除一个或多个哈希表字段hdel myUser ageredisTemplate.opsForHash().delete(“myUser”,“name”);
HLEN key获取指定哈希表中字段的数量hlen myUserredisTemplate.opsForHash().size(“myUser”);
HINCRBY key field increment对指定哈希中的指定字段做运算操作正数为加,负数为减hincrby myUser tel -10redisTemplate.opsForHash().increment(“myUser”, “tel”, -10L);
4.3.2 应用场景

对象数据存储场景:用户信息、商品信息、文章信息、购物车信息。

4.4 Sets(集合)

Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺序但都唯一,有点类似于 Java 中的 HashSet 。当你需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个元素是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。
可以基于 Set 轻易实现交集、并集、差集的操作,比如你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。这样的话,Set 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。

4.4.1 常用命令
命令介绍命令行使用RedisTemplate使用
SADD key member1 member2向指定集合添加一个或多个元素sadd mySet a b credisTemplate.opsForSet().add(“mySet”, “a”, “b”, “c”);
SMEMBERS key获取指定集合中的所有元素smembers mySetredisTemplate.opsForSet().members(“mySet”);
SCARD key获取指定集合的元素数量scard mySetredisTemplate.opsForSet().size(“mySet”);
SISMEMBER key member判断指定元素是否在指定集合中sismember mySet aredisTemplate.opsForSet().isMember(“mySet”,“a”);
SINTER key1 key2获取给定所有集合的交集sinter mySet mySet2redisTemplate.opsForSet().intersect(“mySet”, “mySet2”);
SINTERSTORE destination key1 key2将给定所有集合的交集存储在 destination 中sinterstore inSet mySet mySet2redisTemplate.opsForSet().intersectAndStore(“mySet”, “mySet2”, “inSet”);
SUNION key1 key2获取给定所有集合的并集sunion mySet mySet2redisTemplate.opsForSet().union(“mySet”, “mySet2”);
SUNIONSTORE destination key1 key2将给定所有集合的并集存储在 destination 中sunionstore unionSet mySet mySet2redisTemplate.opsForSet().unionAndStore(“mySet”, “mySet2”,“unionSet”);
SDIFF key1 key2获取给定所有集合的差集key1-key2sdiff mySet mySet2redisTemplate.opsForSet().difference(“mySet”,“mySet2”);
SDIFFSTORE destination key1 key2将给定所有集合的差集存储在 destination 中sdiffstore diffSet mySet mySet2redisTemplate.opsForSet().differenceAndStore(“mySet”, “mySet2”, “diffSet”);
SPOP key count随机移除并获取指定集合中一个或多个元素spop mySet2 2redisTemplate.opsForSet().pop(“mySet2”,2);
SRANDMEMBER key count随机获取指定集合中指定数量的元素srandmember mySet 2redisTemplate.opsForSet().randomMembers(“mySet”,2);
4.4.2 应用场景
  • 需要存放的数据不能重复的场景:文章点赞、动态点赞
  • 需要获取多个数据源交集、并集和差集的场景:共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集)
  • 需要随机获取数据源中的元素的场景:抽奖系统、随机点名

4.5 Sorted Sets(有序集合)

Sorted Set 又称为Zset 类似于 Set,但和 Set 相比,Sorted Set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。有点像是 Java 中 HashMap 和 TreeSet 的结合体。

4.5.1 常用命令
命令介绍命令行使用RedisTemplate使用
ZADD key score1 member1 score2 member2向指定有序集合添加一个或多个元素zadd myZSet 100 a 88 b 56 cSet<ZSetOperations.TypedTuple> tuples = new HashSet<>();tuples.add(new DefaultTypedTuple<>(“a”, 100.0)); tuples.add(new DefaultTypedTuple<>(“b”, 88.0));tuples.add(new DefaultTypedTuple<>(“c”, 56.0)); redisTemplate.opsForZSet().add(“myZSet”, tuples);
ZCARD KEY获取指定有序集合的元素数量zcard myZSetredisTemplate.opsForZSet().size(“myZSet”);
ZSCORE key member获取指定有序集合中指定元素的 score 值zscore myZSet aredisTemplate.opsForZSet().score(“myZSet”, “a”);
ZINTERSTORE destination numkeys key1 key2将给定所有有序集合的交集存储在 destination 中,对相同元素对应的 score 值进行 SUM 聚合操作,numkeys 为集合数量zinterstore zong 2 yuwen shuxueredisTemplate.opsForZSet().intersectAndStore(“yuwen”, “shuxue”, “zong”);
ZUNIONSTORE destination numkeys key1 key2求并集,其它和 ZINTERSTORE 类似zunionstore bing 2 yuwen shuxueredisTemplate.opsForZSet().unionAndStore(“yuwen”, “shuxue”, “bing”);
ZDIFFSTORE destination numkeys key1 key2求差集,其它和 ZINTERSTORE 类似zdiffstore diff 2 yuwen shuxueredisTemplate.opsForZSet().differenceAndStore(“yuwen”, Collections.singletonList(“shuxue”),"diff ");
ZRANGE key start end获取指定有序集合 start 和 end 之间的元素(score 从低到高)zrange myZSet 0 -1redisTemplate.opsForZSet().range(“myZSet”, 0, -1);
ZREVRANGE key start end获取指定有序集合 start 和 end 之间的元素(score 从高到底zrevrange myZSet 0 -1redisTemplate.opsForZSet().reverseRange(“myZSet”, 0, -1);
ZREVRANK key member获取指定有序集合中指定元素的排名(score 从大到小排序)zrevrank myZSet aredisTemplate.opsForZSet().reverseRank(“myZSet”, “a”);
4.5.2 应用场景
  • 需要随机获取数据源中的元素根据某个权重进行排序的场景:各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、游戏中的段位排行榜、话题热度排行榜

4.6 Bitmaps(位图)

Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。
你可以将 Bitmap 看作是一个存储二进制数字(0 和 1)的数组,数组中每个元素的下标叫做 offset(偏移量)。

4.6.1 常用命令
命令介绍命令行使用RedisTemplate使用
SETBIT key offset value设置指定 offset 位置的值setbit myBit 1000 1redisTemplate.opsForValue().setBit(“myBit”, 1000L, true);
GETBIT key offset获取指定 offset 位置的值getbit myBit 1000redisTemplate.opsForValue().getBit(“myBit”,1000L);
BITCOUNT key start end获取 start 和 end 之间值为 1 的元素个数bitcount myBit 3 0redisTemplate.execute((RedisCallback) connection -> connection.bitCount(“myBit”.getBytes(), 3L, 1L));
BITOP operation destkey key1 key2对一个或多个 Bitmap 进行运算,可用运算符有 AND, OR, XOR 以及 NOTbitop or dest a bredisTemplate.execute((RedisCallback) connection -> connection.bitOp(RedisStringCommands.BitOperation.OR, new byte[10], “myBit”.getBytes()));
4.6.2 应用场景
  • 需要保存状态信息(0/1 即可表示)的场景:用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。

4.7 HyperLogLog(基数统计)

HyperLogLog (简称HLL) 是一种有名的基数计数概率算法 ,基于 LogLog Counting(LLC)优化改进得来,并不是 Redis 特有的,Redis 只是实现了这个算法并提供了一些开箱即用的 API。Redis 提供的 HyperLogLog 占用空间非常非常小,只需要 12k 的空间就能存储接近2^64个不同元素。
Redis 对 HyperLogLog 的存储结构做了优化,采用两种方式计数:
稀疏矩阵:计数较少的时候,占用空间很小。
稠密矩阵:计数达到某个阈值的时候,占用 12k 的空间。

4.7.1 常用命令
命令介绍命令行使用RedisTemplate使用
PFADD key element1 element2添加一个或多个元素到 HyperLogLog 中pfadd myhll a b credisTemplate.opsForHyperLogLog().add(“myhll”, “a”, “b”, “c”);
PFCOUNT key1 key2获取一个或者多个 HyperLogLog 的唯一计数pfcount myhll myhll2redisTemplate.opsForHyperLogLog().size(“myhll”,“myhll2”);
PFMERGE destkey sourcekey1 sourcekey2将多个 HyperLogLog 合并到 destkey 中,destkey 会结合多个源,算出对应的唯一计数pfmerge desthll myhll myhll2redisTemplate.opsForHyperLogLog().union(“desthll”, “myhll”, “myhll2”);
4.7.2 应用场景

数量量巨大(百万、千万级别以上)的计数场景:热门网站每日/每周/每月访问 ip 数统计、热门帖子 uv 统计

4.8 Geospatial indexes (地理空间)

Geospatial indexes (地理空间索引,简称 GEO) 主要用于存储地理位置信息,基于 Sorted Set 实现。通过 GEO 我们可以轻松实现两个位置距离的计算、获取指定位置附近的元素等功能。

4.8.1 常用命令
命令介绍命令行使用RedisTemplate使用
GEOADD key longitude1 latitude1 member1添加一个或多个元素对应的经纬度信息到 GEO 中geoadd myGeo 116.404844 39.923678 user1 116.479152 39.938174 user2Map<String, Point> map = new HashMap<>(); map.put(“user1”, new Point(new Point(116.404844, 39.923678))); map.put(“user2”, new Point(new Point(116.479152, 39.938174))); redisTemplate.opsForGeo().add(“myGeo”, map);
GEODIST key member1 member2 M/KM/FT/MI返回两个给定元素之间的距离geodist myGeo user1 user2 kmredisTemplate.opsForGeo().distance(“myGeo”,“user1”,“user2”, Metrics.KILOMETERS);
GEORADIUS key longitude latitude radius distance获取指定位置附近 distance 范围内的其他元素,支持 ASC(由近到远)、DESC(由远到近)、Count(数量) 等参数georadius myGeo 116.419504 39.929654 3 kmCircle circle = new Circle(new Point(116.419504, 39.929654), new Distance(3, Metrics.KILOMETERS)); redisTemplate.opsForGeo().radius(“myGeo”, circle);
4.8.2 应用场景

需要管理使用地理空间数据的场景:附近的人

4.9 Bitfields(位域)

Bitfields 可以设置、增加和获取任意位长度的整数值。可以对从无符号1位整数到有符号63位整数的任何值进行运算。
这些值是使用二进制编码的 Redis String 存储的。位域支持原子读、写和增量操作,是管理计数器和类似数值的好选择。

4.9.1 应用场景和命令

假设英雄联盟中,需要为每个玩家维护两个关键指标:金币总量和补刀数量,这些计数器的宽度应至少为 32 位。
可以用每个玩家的一个位字段来表示这些计数器,使用偏移量 0记录金币 1记录补刀数 。

新玩家以 1000 金币开始(计数器偏移量0 )

bitfield player1 set u32 #0 1000
BitFieldSubCommands bitFieldSubCommands =BitFieldSubCommands.create(); 
bitFieldSubCommands .set(BitFieldSubCommands.BitFieldType.unsigned(32)).valueAt(0).to(1000);
redisTemplate.opsForValue().bitField("player1", bitFieldSubCommands);

补了一个小兵后,获得的 50 金币并让补刀数增加1(偏移量 1)。

bitfield player1 incrby u32 #0 50 incrby u32 #1 1
  BitFieldSubCommands bitFieldSubCommands = BitFieldSubCommands.create();
  bitFieldSubCommands.incr(BitFieldSubCommands.BitFieldType.unsigned(32)).valueAt(0).by(50);
  bitFieldSubCommands.incr(BitFieldSubCommands.BitFieldType.unsigned(32)).valueAt(1).by(1);
  redisTemplate.opsForValue().bitField("player1", bitFieldSubCommands);

买了一把暴风大剑 999 金币

bitfield player1 incrby u32 #0 -999
 bitFieldSubCommands.incr(BitFieldSubCommands.BitFieldType.unsigned(32)).valueAt(0).by(-999);
 redisTemplate.opsForValue().bitField("player1", bitFieldSubCommands);

读取玩家的统计数据

bitfield player1 get u32 #0 get u32 #1
bitFieldSubCommands.get(BitFieldSubCommands.BitFieldType.unsigned(32)).valueAt(0)
.get(BitFieldSubCommands.BitFieldType.unsigned(32)).valueAt(1);
redisTemplate.opsForValue().bitField("player1", bitFieldSubCommands);

在这里插入图片描述

4.10 Streams(流)

Stream 是 Redis 5.0 版本中新增的一种数据结构,它是一个高性能、持久化的消息队列,可以用于实现消息的发布和订阅。Stream 可以看作是一个有序的消息队列,每个消息都有一个唯一的 ID,可以根据 ID 进行消息的查找、删除和确认。在 Stream 中,消息以键值对的形式存储,可以存储任意类型的数据。Stream 还支持多个消费者组,每个消费者组可以独立消费消息,避免消息重复消费。Stream 的引入使得 Redis 在消息队列领域更具竞争力,同时也为开发者提供了一种高效、可靠的消息处理方式。

4.10.1 常用命令

消息队列相关命令

命令说明
XADD添加消息至队列末尾
XTRIM对流进行修剪,限制长度
XDEL删除消息
XLEN获取流包含的元素数量,即消息长度
XRANGE获取消息列表,会自动过滤已经删除的消息
XREAD以阻塞或非阻塞方式获取消息列表

消费者组相关命令

命令说明
XGROUP CREATE创建消费者组
XREADGROUP GROUP读取消费者组中的消息
XACK将消息标记为"已处理"
XGROUP SETID为消费者组设置新的最后递送消息ID
XGROUP DELCONSUMER删除消费者
XGROUP DESTROY删除消费者组
XPENDING显示待处理消息的相关信息
XCLAIM转移消息的归属权
XINFO查看流和消费者组的相关信息
XINFO GROUPS打印消费者组的信息
XINFO STREAM打印流信息

Streams 懒得继续写了,以后应用到再补充吧

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值