Redis設定Key/value的規則定義和注意事項(附工具類)

YClimb發表於2018-11-01

對於redis的儲存key/value鍵值對,經過多次踩坑之後,我們總結了一套規則;這篇文章主要講解定義key/value鍵值對時的定義規則和注意事項。


前面一篇文章講了如何定義Redis的客戶端和Dubbo整合儲存器;當我們真正開始開發的時候,就會突然發現,有點不知道如何去定義Redis的Key和Value值格式,不要著急,馬上我們就可以明白如何去定義和使用,下面我們開始講解如何定義。

Spring+Dubbo整合Redis的兩種解決方案

1、redis value 值格式

在Java常規開發中,我們需要有物件導向的思想,相對於物件來說,比較常用且能快速轉換的格式就是 JSON 了;比較常用的Java處理JSON資料有三個比較流行的類庫FastJSONGsonJackson,他們的優劣點這裡我就不一一介紹了,本文用阿里的FastJSON

上面提到了JSON,這是因為在Redis的儲存中,我們使用它來儲存value值,為什麼要這樣做呢?主要是因為json格式有如下幾種好處:

· 1.標準,主流資料交換格式
· 2.簡單,結構清晰,相對於XML來說更加的輕量級,易於解析
· 3.語言無關,任何語言都能輕鬆搞它
· 4.型別安全,值是有型別的,比如整數、字串、布林等
複製程式碼

下面我們來看看如何使用json來儲存value,程式碼如下:


/**
 * 在redis資料庫中插入 key和value 並且設定過期時間
 *
 * @param key k
 * @param value v
 * @param exp   過期時間 s
 * @return boolean
 */
@Override
public boolean set(String key, V value, int exp) {
    Jedis jedis = null;
    // 將 value 轉換成 json 物件
    // String jKey = JSON.toJSONString(key);
    String jValue = JSON.toJSONString(value);
    // 操作是否成功
    boolean isSucess = true;
    if (StringUtils.isEmpty(key)) {
        LOG.info("key is empty");
        return false;
    }
    try {
        // 獲取客戶端物件
        jedis = redisCache.getResource();
        // 執行插入
        jedis.setex(key, exp, jValue);
    } catch (Exception e) {
        LOG.info("client can't connect server");
        isSucess = false;
        if (null != jedis) {
            // 釋放jedis物件
            redisCache.brokenResource(jedis);
        }
        return false;
    } finally {
        if (isSucess) {
            // 返還連線池
            redisCache.returnResource(jedis);
        }
    }
    return true;
}
複製程式碼

程式碼中redis value在儲存前我們對其做了一次轉換,將物件V轉換為json物件後儲存;下面我們來看看在redis中value值的格式:

zhangsan

上面我們可以看到在redis視覺化工具rdm(Redis Desktop Manager)中,key鍵對應的value用json非常清晰的顯示出來了,非常方便我們查閱redis中儲存的資料。

不知道大家注意到沒有,上面的程式碼中有一行我是註釋掉了,程式碼如下:

// String jKey = JSON.toJSONString(key);
複製程式碼

這一行的意思是將key鍵也json化,不是說json非常友好嗎?那為什麼要註釋這一行呢?下面為大家解釋為何要這樣做。

首先,使用json格式的資料都會變成一個josn格式的String字串,比如 "zhangsan" ,當這個字串作為key儲存時,預設會帶有json的特性,那就是雙引號 "" 也會帶入到redis的key設定中,所以在rdm中我們看到的key值都會預設帶上 "" ,這樣著實不是非常的美觀,特別是對於我們的複雜業務而言,後面會給大家講如何在rdm中使用key值規則定義業務線資料夾。

json zhangsan

2、redis key 鍵格式

上面講了簡單的key儲存,如 zhangsan 的儲存,此時普通的需求可以滿足;然而在實際業務中,往往key鍵的儲存會非常的複雜,比如我們現在有一個需求:

需求:根據基礎資料系統中的資料字典型別查詢對應的字典集合
複製程式碼

這時,我們需要關注的業務就變得複雜了,就不能使用常規的key鍵儲存方式,上面的需求大致可以拆分為:

1.系統:基礎資料系統
2.模組:資料字典
3.方法:根據資料字典型別查詢
4.引數:字典型別
複製程式碼

為什麼要這樣拆分呢?為了可讀性;也為了抽象出key儲存規則;因為業務複雜情況下,我們定義的key鍵太多時就不便於管理,也不便於查詢,以 系統-模組-方法-引數 這樣的規則定義,我們可以很清晰的瞭解redis key儲存的值是做了什麼事情,而且rdm中也可以以此來分組,後面會講到。

下面貼上根據此規則定義抽象出的redis工具類:

package com.yclimb.mdm.redis;

/**
 * Redis 工具類
 *
 * @author yclimb
 * @date 2018/4/19
 */
public class RedisUtils {

    /**
     * 主資料系統標識
     */
    public static final String KEY_PREFIX = "mdm";
    /**
     * 分割字元,預設[:],使用:可用於rdm分組檢視
     */
    private static final String KEY_SPLIT_CHAR = ":";

    /**
     * redis的key鍵規則定義
     * @param module 模組名稱
     * @param func 方法名稱
     * @param args 引數..
     * @return key
     */
    public static String keyBuilder(String module, String func, String... args) {
        return keyBuilder(null, module, func, args);
    }

    /**
     * redis的key鍵規則定義
     * @param module 模組名稱
     * @param func 方法名稱
     * @param objStr 物件.toString()
     * @return key
     */
    public static String keyBuilder(String module, String func, String objStr) {
        return keyBuilder(null, module, func, new String[]{objStr});
    }

    /**
     * redis的key鍵規則定義
     * @param prefix 專案字首
     * @param module 模組名稱
     * @param func 方法名稱
     * @param objStr 物件.toString()
     * @return key
     */
    public static String keyBuilder(String prefix, String module, String func, String objStr) {
        return keyBuilder(prefix, module, func, new String[]{objStr});
    }

    /**
     * redis的key鍵規則定義
     * @param prefix 專案字首
     * @param module 模組名稱
     * @param func 方法名稱
     * @param args 引數..
     * @return key
     */
    public static String keyBuilder(String prefix, String module, String func, String... args) {
        // 專案字首
        if (prefix == null) {
            prefix = KEY_PREFIX;
        }
        StringBuilder key = new StringBuilder(prefix);
        // KEY_SPLIT_CHAR 為分割字元
        key.append(KEY_SPLIT_CHAR).append(module).append(KEY_SPLIT_CHAR).append(func);
        for (String arg : args) {
            key.append(KEY_SPLIT_CHAR).append(arg);
        }
        return key.toString();
    }

    /**
     * redis的key鍵規則定義
     * @param redisEnum 列舉物件
     * @param objStr 物件.toString()
     * @return key
     */
    public static String keyBuilder(RedisEnum redisEnum, String objStr) {
        return keyBuilder(redisEnum.getKeyPrefix(), redisEnum.getModule(), redisEnum.getFunc(), objStr);
    }

}

複製程式碼

上面程式碼中有此文字描述 分割字元,預設[:],使用:可用於rdm分組檢視 ;redis key預設使用冒號分割,好處在於可以在rdm中以資料夾的形式分組檢視,如圖:

冒號分組

3、使用列舉類來定義規則

上面的工具類中的有如下程式碼,使用了列舉的形式來賦值:

/**
 * redis的key鍵規則定義
 * @param redisEnum 列舉物件
 * @param objStr 物件.toString()
 * @return key
 */
public static String keyBuilder(RedisEnum redisEnum, String objStr) {
    return keyBuilder(redisEnum.getKeyPrefix(), redisEnum.getModule(), redisEnum.getFunc(), objStr);
}
複製程式碼

下面是列舉類程式碼:

package com.yclimb.mdm.redis;

/**
 * Redis 列舉類
 *
 * @author yclimb
 * @date 2018/4/19
 */
public enum RedisEnum {

    /**
     * 資料字典Service - 根據字典型別查詢字典資料
     */
    MDM_MSTDATADICTIONARYSERVICE_QUERYLISTBYENTITYREDIS(
            RedisUtils.KEY_PREFIX, "MstDataDictionaryService", "queryListByEntityRedis", "資料字典Redis快取");

    /**
     * 系統標識
     */
    private String keyPrefix;
    /**
     * 模組名稱
     */
    private String module;
    /**
     * 方法名稱
     */
    private String func;
    /**
     * 描述
     */
    private String remark;

    RedisEnum(String keyPrefix, String module, String func, String remark) {
        this.keyPrefix = keyPrefix;
        this.module = module;
        this.func = func;
        this.remark = remark;
    }

    getter and setter....
}

複製程式碼

使用上面的列舉類,可以根據模組和方法定義需要的列舉型別,便於管理和維護,使用起來也非常方便,使用程式碼如下:


@Override
public List<MstDataDictionary> queryListByEntityRedis(MstDataDictionary mstDataDictionary) {
	// redis key 獲取
	String redisKey = RedisUtils.keyBuilder(RedisEnum.MDM_MSTDATADICTIONARYSERVICE_QUERYLISTBYENTITYREDIS, (null == mstDataDictionary ? "" : mstDataDictionary.toString()));
	// 查詢redis快取
	List<MstDataDictionary> mstDataDictionaryList = (List<MstDataDictionary>) redisCacheService.get(redisKey);
	// 如果沒有快取則查詢資料庫後賦值
	if (mstDataDictionaryList == null || mstDataDictionaryList.size() <= 0) {
		mstDataDictionaryList = mstDataDictionaryMapper.queryListByEntity(mstDataDictionary);
		redisCacheService.set(redisKey, mstDataDictionaryList);
	}
	return mstDataDictionaryList;
}
複製程式碼

OK,到這裡就差不多講完了,根據上面所說的分模組方式,自定義redis的key鍵名稱,value值格式使用json來儲存;

對於key鍵的規則定義也可以使用 Constants 常量類來實現,具體規則看個人愛好和需求。

結語

具體的定義規則工具類程式碼都在上面了,也是原始碼。

到此本文就結束了,關注公眾號檢視更多推送!!!


關注我的公眾號


相關文章