Redis系列之常见数据类型应用场景
- 
String
- 簡單介紹
 - 常見命令
 - 應用場景
 
 - 
Hash
- 簡單介紹
 - 常見命令
 - 應用場景
 
 - 
List
- 簡單介紹
 - 常見命令
 - 應用場景
 
 - 
Set
- 簡單介紹
 - 常見命令
 - 應用場景
 
 - 
Sorted Set(Zset)
- 簡單介紹
 - 常見命令
 - 應用場景
 
 - 
Bitmap
- 簡單介紹
 - 常見命令
 - 應用場景
 
 - 附錄
 
Redis支持多種數據類型,比如String、hash、list、Set、SortedSet、Streams、Bitmap、Hyperloglog、Geo(物理位置)等等,在官網也給出了說明,本博客就挑一些比較常有的數據類型說說,本文例子基于Redisson實現
String
簡單介紹
在Redis中,所有的數據都是key-value的數據結構存儲的,那么在Redis中這個string類型的value值只能存儲String類型的數據?其實不然,redis中string類型的value值是可以支持多種類型的,比如String、Number、Float、Bits等等,但是最大還是只能存儲512M。Redis中key也是string類型存儲的,所以最大也只能存儲512M
常見命令
set、get命令就不演示了,下面給出一些常有命令
批量設置多個key
mset tkey1 tvalue tkey2 111
批量獲取多個key值
mget tkey1 tkey2
獲取長度
strlen tkey
字符串后面追加內容
append tkey tstring
獲取指定范圍的字符
# 取0~3之間的字符,返回1tst
getrange tkey 0 3
key進行遞增(整數)
# 返回1
incr ikey
# 遞增指定大小的值,返回124
incrby ikey 124
key進行遞增(浮點數)
# 設置初始浮點數值
set fkey 1.2
# 在原來基礎上遞增2.4,返回3.6
incryfloat fkey 2.4
加上key過期時間
expire tkey 10
分布式鎖實現,set if not exists,可以使用setnx單個命令,也可以使用set結合nx命令來實現
# set tkey過期時間10秒,nx:如果鍵不存在時設置
set tkey aaa ex 10 nx
# setnx命令,相當于set和nx命令一起用
setnx tkey aaa
EX : 設置指定的到期時間(以秒為單位)。
PX : 設置指定的到期時間(以毫秒為單
NX : 僅在鍵不存在時設置鍵。
XX : 只有在鍵已存在時才設置。
String 更多指令請參考官網文檔:https://redis.io/commands/?group=string
應用場景
對于Redis String類型的應用場景也比較多,比如很常有的做緩存處理,也可以用于分布式鎖、分布式ID
分布式鎖的實現主要依賴于命令
setnx
分布式ID主要是利用
incr這個命令
基于Redis實現一個分布式ID生成器
package com.example.redis.common.handlers;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
 * <pre>
 *      Redis分布式ID生成器
 * </pre>
 *
 * <pre>
 * 修改記錄
 *    修改后版本:     修改人:  修改日期: 2023/11/07 14:18  修改內容:
 * </pre>
 */
@Component
public class RedisIdentifierGenerator implements IdentifierGenerator {
    @Resource
    private RedisTemplate redisTemplate;
    @Override
    public Number nextId(Object entity) {
        String key = entity.getClass().getName();
        return redisTemplate.opsForValue().increment(key);
    }
}
Hash
簡單介紹
Hash哈希,數據類型也是一種比較常見的數據結構,相對于Redis的string類型而言,其實就是多了一層key(field),所以說只要string類型適用的場景,hash都是支持的
常見命令
hash設置key為hkey,field為a的值
hset hkey a aaaa
獲取hkey的field值
hget hkey a
設置多個field值
hmset hkey a 1 b 2 c 3 d 4
獲取多個field值
hmget hkey a b c d
獲取key所有的field
hkeys hkey
獲取key所有field的值
hvals hkey
獲取key所有fileld和值
hgetall hkey
給key某個字段field添加值
hincrby hkey a 10
對于Hash的更多命令,請參考:https://redis.io/commands/?group=hash
應用場景
對于hash的應用場景,其實只要redis string類型適用的,hash都是適用的,不過hash這種特殊的數據結構,還是適用于一些特殊場景的
- 存儲一個對象類的數據,這個對象的多個字段就對應hash的field
 - 存儲一些統計類的數據,比如訪問量、點擊量等等
 
如圖,如果要統計博客的pv、uv還有評論數量(evaluation_count),隨著博客數量的增加存儲到數據庫里,后面肯定會查詢比較慢,所以可以使用redis進行緩存
使用Redisson來寫一個例子:
  @Resource
    private RedissonClient redissonClient;
    @Test
    void contextLoads() throws ExecutionException, InterruptedException {
        RMap<Object, Object> redissonClientMap = redissonClient.getMap("recordMap");
        Map<String,Integer> map = new HashMap<>();
        map.put("pv" , 1000);
        map.put("uv" , 1500);
        map.put("evaluation_count",30)
        redissonClientMap.putAll(map);
        System.out.println(redissonClientMap.addAndGet("pv", 2));
    }   
List
簡單介紹
redis中的數據類型存儲有序的字符串列表,元素是可以重復,列表的最大長度為2^32-1個元素(4294967295),即每個列表超過40億個元素
常見命令
左右添加元素
# 左邊添加元素
lpush queueList a
lpush queueList b c
# 右邊添加元素
rpush queueList d e
左右彈出第一條
# 左邊彈出一個元素
lpop queueList
# 右邊彈出一個元素
rpop queueList
左右彈出一個元素,并且設置超時,直到無數據彈出或者超時
blpop queueList 10
brpop queueList 10
應用場景
- 
微信公眾號、微博等消息流列表
RDeque<Object> recordList = redissonClient.getDeque("recordList"); recordList.addFirst("1.新聞1"); recordList.addFirst("2.新聞2"); recordList.addFirst("3.新聞3"); IntStream.range(0,3).forEach(a->{ System.out.println(recordList.poll()); }); - 
消息隊列,使用redis也可以實現消息隊列,比如使用
rpush/lpop實現簡單隊列;blpop或者是brpop來實現阻塞讀取隊列;補充說明,同時stream、pub/sub(訂閱發布模式)、sortedSet等等也是可以實現的不過還是不建議使用Redis來實現消息隊列,因為我們已經有成熟的MQ框架,使用redis實現隊列有可能有下面的問題:
- 存在內存,可能會有數據丟失,不能重復消費
 - 消費后不能回應,沒有ack確認機制
 
 
Set
簡單介紹
Redis中的Set類型是無序集合,最大存儲數量為2^32-1,大概有40億左右,添加、刪除元素的時間復雜度都是O(1)
常見命令
添加一個或者多個元素
sadd skey a b c d e f g h
獲取所有的元素
smembers skey
獲取集合元素的個數
scard skey
隨機獲取一個元素
srandmember skey
隨機彈出一個元素
spop skey
彈出指定的元素
# 如果兩個元素都有,返回2
srem skey a g
檢查元素是否存在
# 元素存在返回1
sismember skey e
獲取前一個集合有,而后面一個集合沒有的元素
sdiff skey skey1
獲取集合的交集
sinter skey skey1
獲取集合的并集
sunion skey skey1
Set的更多命令請參考:https://redis.io/commands/?group=set
應用場景
- 
抽獎程序,利用
spop跟standmember隨機彈出元素RSet<String> recordSet = redissonClient.getSet("recordSet"); List<String> members = Lists.newArrayList("alice", "tim","tom" , "風清揚", "jack" ); recordSet.addAll(members); RFuture<Set<String>> threeSet = recordSet.removeRandomAsync(3 ); RFuture<Set<String>> twoSet = recordSet.removeRandomAsync(2 ); RFuture<Set<String>> oneSet = recordSet.removeRandomAsync(1 ); System.out.println("三等獎:"+threeSet.get()); System.out.println("二等獎:"+twoSet.get()); System.out.println("一等獎:"+oneSet.get()); - 
集合交集(sinter)、并集(sunion)的場景,可以實現共同關注等場景
RSet<Object> tom = redissonClient.getSet("tom"); tom.addAll(Lists.newArrayList("令狐沖","james","風清揚")); RSet<Object> jack = redissonClient.getSet("jack"); jack.addAll(Lists.newArrayList("令狐沖","tim","jack")); System.out.println("共同關注的人:"+tom.readIntersectionAsync("jack").get()); - 
sadd 集合存儲,實現點贊、簽到的業務場景
 
Sorted Set(Zset)
簡單介紹
相對于set來說,sorted set是一種有序的set,排序是根據每個元素的score排序的,score相同時根據key的ASCII碼排序
常見命令
批量添加元素
zadd z1 10 a 20 b 30 c 40 d 50 e 60 f 70 g 80 h 90 i
根據分數從低到高
zrange z1 0 -1 withscore
根據分數從高到低
zrevrange z1 0 -1 withscores
根據分數范圍取值
zrangebyscore z1 20 30
移除元素
zrem z1 i
獲取有序集合個數
zcard z1
給某個元素加分值
zincrby z1 20 a
獲取范圍內的個數
zcount z1 50 60
返回指定元素的索引值
# 假如d元素排在第4位,索引值就返回3
zrank z1 d
獲取元素的分數
zscore z1 h
Sorted Set的更多命令請參考:https://redis.io/commands/?group=sorted_set
應用場景
- 
排行榜
RScoredSortedSet<String> school = redissonClient.getScoredSortedSet("school"); school.add(60, "tom"); school.add(60, "jack"); school.add(60, "tim"); school.addScore("tom", 20); school.addScore("jack", 10); school.addScore("tim", 30); RFuture<Collection<ScoredEntry<String>>> collectionRFuture = school.entryRangeReversedAsync(0, -1); Iterator<ScoredEntry<String>> iterator = collectionRFuture.get().iterator(); System.out.println("成績從高到低排序"); while(iterator.hasNext()) { ScoredEntry<String> next = iterator.next(); String value = next.getValue(); System.out.println(value); } RFuture<Collection<ScoredEntry<String>>> collectionRFuture1 = school.entryRangeReversedAsync(0, 2); Iterator<ScoredEntry<String>> iterator1 = collectionRFuture1.get().iterator(); System.out.println("成績前三名"); while (iterator1.hasNext()) { System.out.println(iterator1.next().getValue()); } 
Bitmap
簡單介紹
位圖不是實際的數據類型,而是String類型中定義的一種面向位的操作,所以這個位圖的最大存儲量也是512M??梢匀菁{最少2^32不同的位,可以在不同的位置設置0或者1
常見命令
設置位的值
# 將位2設置為1
setbit permit 2 1
獲取位的值
getbit permit 2
獲取key的為1的個數
# 獲取位為1的總數
bitcount permit
獲取0或者1的第一位
# 獲取key permit 位為1的第一個位置
bitpos permit 1
獲取多個bitmap的位操作,比如& 、|
# 獲取bkey和permit這兩個的&運算,并且賦值給hbit
bitop AND hbit bkey permit
應用場景
- 
實時的數據統計
比如:人員的考勤打卡記錄,例如學生tom每次來上課就將相關的位記錄位1
 
假如當月的第一天、第五天、第十天都來了
setbit tom 1 1
setbit tom 5 1
setbit tom 10 1
如何每月考勤,統計一下這個用戶當月來了幾天
bitcount tom 
也可以應用于統計一個網站一天有多少用戶訪問,例如用戶ID為123、124、125的用戶訪問了csdn
setbit csdn:2023-11-08 123 1
setbit csdn:2023-11-08 124 1
setbit csdn:2023-11-08 125 1
...
# 統計一下當天的訪問次數
bitcount csdn:2023-11-08 
- 存儲用戶權限,比如用1來表示有權限,0表示沒權限,使用位圖可以節省很大的存儲空間
 
附錄
Redis命令查詢網站:https://redis.io/commands/
總結
以上是生活随笔為你收集整理的Redis系列之常见数据类型应用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: Python 数据库应用教程:安装 My
 - 下一篇: Kubernetes: kube-api