Redis手記之數據類型

1.前言

一直以爲自己會redis,但是從沒有系統的學過,對於redis的理解還是隻停留在set key、get key這些基礎的命令上。現在查漏補缺,重新學習一遍,增加一下對redis的瞭解。

2.Redis的key

redis的key除了set 和 get之外。還有exists, expire, keys, expireat, ttl等很多,常用的如下:

命令 說明 demo
exists 檢查當前庫裏面是否存在某個key

127.0.0.1:6379> exists name
(integer) 1

expire

設置key的過期時間,單位秒

pexpire單位是毫秒 pexpireat同毫秒

127.0.0.1:6379> expire name 2000
(integer) 1
expireat 設置key的過期時間,單位時間戳,這個在某些特殊場景還是挺有用的 127.0.0.1:6379> EXPIREAT name 1576234458
(integer) 1
127.0.0.1:6379> ttl name
(integer) 86369
persist 取消key的過期時間,key將永久保存 127.0.0.1:6379> persist name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -1
keys 返回符合條件的key(生產環境慎用 keys *,或者禁用) 127.0.0.1:6379> keys na*
1) "name"
ttl 查看key的剩餘過期時間 127.0.0.1:6379> ttl name
(integer) 1773
rename 重命名一個key,如果newname已存在,則會覆蓋 127.0.0.1:6379> get name
"smallking"
127.0.0.1:6379> set name2 "tom"
OK
127.0.0.1:6379> rename name2 name
OK
127.0.0.1:6379> get name
"tom"
incr 自增+1,如果 key 不存在,那麼 key 的值會先被初始化爲 0 127.0.0.1:6379> set i 1
OK
127.0.0.1:6379> incr i
(integer) 2
127.0.0.1:6379> get i
"2"

3.Redis hash

hash是redis的數據類型之一,比較適合用來存儲對象。語法如下:

命令 說明 demo
hmset

添加一個或者多個鍵值對到key對應的hash表中。以前認爲hmset是hashMapSet的縮寫,後來看到還有一個hset,所以hmset應該hash multi set的縮寫。一次可以設置多個,而hset只能設置一個

127.0.0.1:6379> hmset user01 id 001 name smallking age 18
OK
hmget 得到指定key對應hash表的多個key-value 127.0.0.1:6379> HMGET user01 id name
1) "001"
2) "smallking"
hset和hget 同hmset和hmget不同的是,一次只能操作hash的一個鍵值對 127.0.0.1:6379> hset user01  email [email protected]
(integer) 1
127.0.0.1:6379> hget user01 email
"[email protected]"
hgetall 得到一個hash表的所有字段 127.0.0.1:6379> hgetall user01
1) "id"
2) "001"
3) "name"
4) "smallking"
5) "age"
6) "18"
7) "email"
8) "[email protected]"
hkeys 得到指定hash表的所有key 127.0.0.1:6379> hkeys user01
1) "id"
2) "name"
3) "age"
4) "email"
hvals 得到指定hash表的所有value 127.0.0.1:6379> HVALS user01
1) "001"
2) "smallking"
3) "18"
4) "[email protected]"

除了表中的這些,redis的hash還有其他一些命令,很多命令都是見名知意。hash可以用來存儲對象,但是如果將對象轉爲json字符串,以key-jsonstr存在redis裏更方便,一般不經常修改的對象,可以存jsonstr,但是如果對象要經常修改的話,還是存hash比較方便。

4.Redis list 

一直都將redis的list當成一個java的ArrayList<String> 來看,其實它是個linkedList<String>。當我們想到一個list的時候,list.add()增加元素,list.get(index) 獲得元素,list.size()獲取列表長度,這些功能redis的list都具備:

命令 說明 demo
lpush 在list的頭部添加元素 127.0.0.1:6379> lpush idlist 1 2 3 4 5
(integer) 5
llen llen即 list length 獲取list的長度 127.0.0.1:6379> llen idlist
(integer) 5
lrange  獲取list的一段值  127.0.0.1:6379> lrange idlist 0 100
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
lindex 獲取指定下標的值 127.0.0.1:6379> lindex idlist 3
"2"
lpop 移除並返回第一個元素 127.0.0.1:6379> lpop idlist
"5"
127.0.0.1:6379> lrange idlist 0 100
1) "4"
2) "3"
3) "2"
4) "1"
lpush 在頭部插入一個元素 127.0.0.1:6379> lpush idlist 10
(integer) 5
127.0.0.1:6379> lrange idlist 0 100
1) "10"
2) "4"
3) "3"
4) "2"
5) "1"

redis的list除了以上操作,還有通過BLPOP/BRPOP來實現簡單的消息隊列,這兩個命令都是阻塞的。當程序中有簡單消息隊列的需要,但是對於消息的可靠性性要求不高的時候,可以使用BLPOP/BRPOP來簡單快速的實現消息隊列需求。簡單實現如下:

生產者

import com.smallking.redis.speed.JedisManager;

import redis.clients.jedis.Jedis;

public class Producer {
	
	public static void main(String[] args) {
		Jedis jedis = JedisManager.instance().getJedis();
		Long lpush = jedis.lpush("message", "消息內容:" + Math.random());
		System.out.println("list大小:" + lpush);
	}
	
}

消費者

import java.util.List;

import com.smallking.redis.speed.JedisManager;

import redis.clients.jedis.Jedis;

public class Comsumer {

	public static void main(String[] args) {
		Jedis jedis = JedisManager.instance().getJedis();
		while(true) {
			List<String> list = jedis.blpop(0, "message");
			for(String str : list) {
				System.out.println("處理消息" + str);
			}
		}
	}

}

redis的list通過lrange命令還可以實現定時計算的,並且計算之後就不會更改的排行榜,如去年的班級成績排名,上個月的出勤率等,但是如果是經常變化的list就不推薦用list了,後面會說到可以用sorted set。還有一些時間線很明顯的數據也可以通過list的lpush來實現。

5.Redis set

redis的set存儲的元素是無序且唯一的。除了對set的基礎增刪改查之外,我們還應該靈活運用set的交併插計算來應對一些場景。

命令 說明 demo
sadd  爲一個set集合添加一個或者多個元素 127.0.0.1:6379> sadd user 1 2 3
(integer) 3
smembers 獲得一個set集合的所有元素 127.0.0.1:6379> SMEMBERS user
1) "1"
2) "2"
3) "3"
srem 移除一個或者多個元素 127.0.0.1:6379> SREM user 1 2
(integer) 2
sdiff 求所給集合的差集 127.0.0.1:6379> sadd set1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd set2 2 5 6 7
(integer) 4
127.0.0.1:6379> sdiff set1 set2
1) "1"
2) "3"
3) "4"
sunion 求所給集合的並集 127.0.0.1:6379> sunion set1 set2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
sinter 求交集 127.0.0.1:6379> sinter set1 set2
1) "2"

redis的set集合可以給我們解決很多問題,例如:

  • set的唯一性可以用來做uv統計,一天一個用戶多次訪問本網站算做一次uv,則可以用日期作爲key,當用戶訪問網站的時候直接sadd當前客戶的ID就好了。
  • set的sinter可以用來做好友推薦,需求:現在有2個用戶,如果這兩個用戶的共同好友超過3人,則推薦他們加好友。我們可以用用戶的id作爲key,將用戶的好友存儲在set裏面,sinter userid1 userid2就得到了2個人的共同好友,判斷共同好友的數量,決定是否推薦。
  • 當業務需要求交集並集差集的時候,可以朝着redis set上面想一想,也許一下子就變的簡單了呢。

6.Redis sorted set

sorted set是有序的集合,它給每個set元素都加了一個score分數,通過這個分數來進行排序。

命令 說明 demo
zadd 添加元素 如果元素已則會更新元素的score 127.0.0.1:6379> zadd ganmerank 200.5 xiaowang 300 xiaozhang 400 xiaoli
(integer) 3
zrange 按照下標查詢元素 127.0.0.1:6379> zrange ganmerank 0 100 withscores
1) "xiaowang"
2) "200.5"
3) "xiaozhang"
4) "300"
5) "xiaoli"
6) "400"
zrangebyscore 按照分數來查詢元素 127.0.0.1:6379> zrangebyscore gamerank 1 1000 withscores
1) "xiaowang"
2) "200.5"
3) "xiaozhang"
4) "300"
5) "xiaoli"
6) "400"
zrem 刪除元素 127.0.0.1:6379> zrange gamerank 0 200
1) "xiaowang"
2) "xiaoli"
127.0.0.1:6379> zrem gamerank xiaoli
(integer) 1
127.0.0.1:6379> zrange gamerank 0 -1
1) "xiaowang"
ZINCRBY 給某個元素加分 127.0.0.1:6379> zrange gamerank 0 -1 withscores
1) "xiaowang"
2) "200.5"
127.0.0.1:6379> ZINCRBY gamerank 1 xiaowang
"201.5"

sorted set 很適用一些實時變化的排行場景,比如某論壇的文章排序規則是按照閱讀量,那麼可以用文章的id作爲sorted set的元素,閱讀量作爲score。當一個文章閱讀量發生變化的時候ZINCRBY +1 就好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章