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 |
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 就好了。