天天看點

redis系列:通過通訊錄案例學習hash指令

前言

這一篇文章将講述Redis中的hash類型指令,同樣也是通過demo來講述,其他部分這裡就不在贅述了。

項目Github位址:

https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-hash

案例

demo功能是通訊錄,整個demo的大緻頁面如下

redis系列:通過通訊錄案例學習hash指令

準備工作

首先定義一個key的字首,已經存儲自增id的key

private static final String CONTACTS_KEY_PREFIX = "contacts:";
private static final String CONTACTS_ID_KEY = "contactsID";           

通訊錄相關的key将會以contacts:1、contacts:2、contacts:3的形式存儲

redis操作對象

private RedisTemplate redisTemplate;
//string 指令操作對象
private ValueOperations valueOperations;
//hash 指令操作對象
private HashOperations hashOperatio           

疑惑

如果讀者和我一樣是學Java的,剛聽到hash時的第一反應是這個不是一個算法嗎?當時我也是這樣想的。那麼先來看看hash在Redis中的結構,如下圖(圖檔來源于Redis in Action)。

redis系列:通過通訊錄案例學習hash指令

如果圖看不懂的,我再來介紹下。其實Redis中的hash結構就和mysql中的表類似,把key當做表名,一張表中有多個列名(sub-key),每個列有自己的值(value),然後這張表隻能存放一條資料。不過,這裡的hash結構不會像mysql中固定好的,它可以很友善的增加删除列,例如增加sub-key3删除sub-key1.

redis系列:通過通訊錄案例學習hash指令

新增

指令介紹

先來看看hash中關于新增的一些指令

指令 用例 描述
HSET HSET key field value 設定 key 指定的哈希集中指定字段的值。
HSETNX HSETNX key field value 當field不存在時,才能成功設定值
HMSET HMSET key field value [field value ...] 設定 

key

 指定的哈希集中指定字段的值(多個) 。

接下來看看demo中新增的功能,下圖中點選+按鈕,然後在彈出框中填入name和phone屬性,點選送出後整個新增流程結束。

redis系列:通過通訊錄案例學習hash指令

來看看背景的方法

@RequestMapping(value = "/add",method = RequestMethod.POST)
public boolean add(@RequestBody JSONObject contacts){
    //擷取自增id
    Long contactsId = valueOperations.increment(CONTACTS_ID_KEY, 1);

    contacts.put("id",String.valueOf(contactsId));
    //json轉map,然後存入redis
    hashOperations.putAll(CONTACTS_KEY_PREFIX+contactsId,contacts.getInnerMap());

    return true;
}           
  1. 首先是獲得自增id
  2. 然後将id存入到前端傳過來的json對象中
  3. 調用hashOperations對象的putAll方法将對象傳入到Redis中。(putAll方法其實是調用了hmset指令,源碼如下)
public void putAll(K key, Map<? extends HK, ? extends HV> m) {
    if (!m.isEmpty()) {
        byte[] rawKey = this.rawKey(key);
        Map<byte[], byte[]> hashes = new LinkedHashMap(m.size());
        Iterator var5 = m.entrySet().iterator();

        while(var5.hasNext()) {
            Entry<? extends HK, ? extends HV> entry = (Entry)var5.next();
            hashes.put(this.rawHashKey(entry.getKey()), this.rawHashValue(entry.getValue()));
        }
        //調用hMSet
        this.execute((connection) -> {
            connection.hMSet(rawKey, hashes);
            return null;
        }, true);
    }
}           

清單查詢

同樣先看看相關的擷取值指令

HGET HGET key field 傳回 key 指定的哈希集中該字段所關聯的值
HGETALL HGETALL key 傳回 key 指定的哈希集中所有的字段和值。
HKEYS HKEYS key 傳回 key 指定的哈希集中所有字段的名字。
HMGET HMGET key field [field ...] 傳回 

key

 指定的哈希集中指定字段的值。
HVALS HVALS key 傳回 key 指定的哈希集中所有字段的值。
HSCAN 用于疊代Hash類型中的鍵值對。
HGET和HGETALL指令

來看看HGET和HGETALL在redis用戶端和java中是如何操作的

redis用戶端執行的指令如下

hset key field1 "Hi"
hset key field1 "Hello"
hsetnx key field1 "Hello"
hsetnx key field2 " redis"
hget key field1
hgetall key           

執行結果如下

redis系列:通過通訊錄案例學習hash指令

下面是java代碼

@Test
public void hGetAll() {
    jedis.hset("key", "field1", "Hi");
    redisTemplate.opsForHash().put("key", "field1", "Hello");

    System.out.println(jedis.hsetnx("key", "field1", "Hello"));
    System.out.println(redisTemplate.opsForHash().putIfAbsent("key", "field2", "Hello"));

    System.out.println(jedis.hget("key", "field1"));
    System.out.println(jedis.hgetAll("key"));

    //spring redisTemplate
    System.out.println(redisTemplate.opsForHash().get("key", "field1"));
    System.out.println(redisTemplate.opsForHash().entries("key"));
}           
hset hashKey field1 value1
hset hashKey field2 value2
hkeys hashKey           
redis系列:通過通訊錄案例學習hash指令
@Test
public void hKeys() {
    jedis.hset("hashKey", "field1", "value1");
    jedis.hset("hashKey", "field2", "value2");

    System.out.println(jedis.hkeys("hashKey"));

    //spring redisTemplate
    System.out.println(redisTemplate.opsForHash().keys("hashKey"));
    /**
     * 注:兩次結果傳回的順序是不一樣的,
     * 因為jedis.hkeys傳回的是HashSet(内部使用HashMap)
     * redisTemplate.opsForHash().keys傳回的是LinkHashSet(内部使用LinkHashMap)
     */
}           
hmset key field1 value1 field2 value2 field3 value3
hvals key           
redis系列:通過通訊錄案例學習hash指令
@Test
public void hVals() {
    Map<String, String> map = new HashMap<>(3);
    map.put("field1", "value1");
    map.put("field2", "value2");
    map.put("field3", "value3");

    jedis.hmset("key", map);

    System.out.println(jedis.hvals("key"));

    //spring redisTemplate
    System.out.println(redisTemplate.opsForHash().values("key"));
}           

查詢方法代碼

接着寫個查詢方法,将新增的内容查詢出來

@RequestMapping(value = "/getList",method = RequestMethod.GET)
    public List getList(){
        List list = new ArrayList();

        //擷取聯系人的keys
        Set<String> keys = redisTemplate.keys(CONTACTS_KEY_PREFIX+"*");

        for (String key: keys) {
            Map entries = hashOperations.entries(key);
            list.add(entries);
        }

        return list;
    }           

這個hash查詢多個會不友善些,步驟如下

  1. 擷取相關的key
  2. 循環查找key相關的資料
  3. 将查詢出來的結果添加到list中,傳回

添加屬性

redis系列:通過通訊錄案例學習hash指令

來看看代碼

@RequestMapping(value = "/addAttr", method = RequestMethod.POST)
public boolean addAttr(@RequestBody JSONObject contacts){
    String id = contacts.getString("id");
    String fieldName = contacts.getString("fieldName");
    String fieldValue = contacts.getString("fieldValue");

    hashOperations.put(CONTACTS_KEY_PREFIX+id, fieldName, fieldValue);

    return true;
}           

其實就是用hset指令進行插入

hset contacts:1 address 北京9527号           

删除屬性

HDEL HDEL key field [field ...] 從 key 指定的哈希集中移除指定的域
hset hDelKey filed1 filedValue1
hdel hDelKey filed1
hdel hDelKey filed1           
redis系列:通過通訊錄案例學習hash指令

現在來看看demo中的删除屬性

redis系列:通過通訊錄案例學習hash指令

代碼如下

@RequestMapping(value = "/delAttr", method = RequestMethod.POST)
public boolean delAttr(@RequestBody JSONObject contacts){

    String id = contacts.getString("id");
    String fieldName = contacts.getString("fieldName");
    hashOperations.delete(CONTACTS_KEY_PREFIX+id, fieldName);

    return true;
}           

其他指令

HEXISTS HEXISTS key field 傳回hash裡面field是否存在
HINCRBY HINCRBY key field increment 增加 

key

 指定的哈希集中指定字段的數值
HINCRBYFLOAT HINCRBYFLOAT key field increment 同上,加的是浮點型
HLEN HLEN key

key

 指定的哈希集包含的字段的數量。
HSTRLEN HSTRLEN key field 傳回hash指定field的value的字元串長度

建議學習的人最好每個指令都去敲下,加深印象。下面詩句送給你們。

紙上得來終覺淺,絕知此事要躬行。————出自《冬夜讀書示子聿》