Redis 设置 Key/value 的规则定义和注意事项(附工具类)

栏目: 数据库 · 发布时间: 6年前

内容简介:对于redis的存储key/value键值对,经过多次踩坑之后,我们总结了一套规则;这篇文章主要讲解定义key/value键值对时的定义规则和注意事项。前面一篇文章讲了如何定义Redis的客户端和Dubbo集成存储器;当我们真正开始开发的时候,就会突然发现,有点不知道如何去定义Redis的Key和Value值格式,不要着急,马上我们就可以明白如何去定义和使用,下面我们开始讲解如何定义。Spring+Dubbo集成Redis的两种解决方案

对于 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值的格式:

Redis 设置 Key/value 的规则定义和注意事项(附 <a href='https://www.codercto.com/tool.html'>工具</a> 类)

上面我们可以看到在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值规则定义业务线文件夹。

Redis 设置 Key/value 的规则定义和注意事项(附工具类)

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中以文件夹的形式分组查看,如图:

Redis 设置 Key/value 的规则定义和注意事项(附工具类)

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 常量类来实现,具体规则看个人爱好和需求。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数学与泛型编程

数学与泛型编程

[美]亚历山大 A. 斯捷潘诺夫(Alexander A. Stepanov)、[美]丹尼尔 E. 罗斯(Daniel E. Rose) / 爱飞翔 / 机械工业出版社 / 2017-8 / 79

这是一本内容丰富而又通俗易懂的书籍,由优秀的软件设计师 Alexander A. Stepanov 与其同事 Daniel E. Rose 所撰写。作者在书中解释泛型编程的原则及其所依据的抽象数学概念,以帮助你写出简洁而强大的代码。 只要你对编程相当熟悉,并且擅长逻辑思考,那么就可以顺利阅读本书。Stepanov 与 Rose 会清晰地讲解相关的抽象代数及数论知识。他们首先解释数学家想要解决......一起来看看 《数学与泛型编程》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试