对于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可视化工具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值规则定义业务线文件夹。

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

结语

具体的定义规则工具类代码都在上面了,也是源码。

到此本文就结束了,关注公众号查看更多推送!!!



Redis设置Key/value的规则定义和注意事项(附工具类)的更多相关文章

  1. 【redis】redis的 key的命名规则

    key的命名规则 定义为 MS-TEN:SESSION_KEY_IN_LOGIN_NAME:fqh 使用:进行分割,这样存入redis的是有层次结构的,如下

  2. Redis设置Key的过期时间 – EXPIRE命令

    EXPIRE key seconds 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除. 操作key对生存时间的影响 生存时间可以通过使用 DEL 命令来删除整个 ...

  3. redis设置key总结

    1.redisclient.hgetall(keyVal)  : 返回哈希表 key 中,所有的域和值

  4. Redis五种数据类型-设置key的过期时间

    1.redis命令客户端 [root@localhost bin]# ./redis-cli 127.0.0.1:6379> #是否运行着 127.0.0.1:6379> ping PON ...

  5. Redis设置和更新Key的过期时间

    EXPIRE key seconds 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除. 在 Redis 中,带有生存时间的 key 被称为『易失的』(volati ...

  6. redis的key设置每天凌晨过期的思路

    设置key凌晨过期的思路 设置key的值的时候,计算下当前时间到第二天凌晨的时间差,设置key的过期时间. 利用定时任务,每天凌晨将需要过期的key删除. 应用场景 按天为维度,限制用户对资源的访问次 ...

  7. Redis设置记录

    首先大前提是,这个redis使用的外网端口,需要在防火墙或者安全组中打开 正常在redis配置文件里有个bind,这个默认是127.0.0.1,如果不修改,就是内网可以访问. 这里有个点需要提一下,就 ...

  8. Redis大 key的发现与删除方法全解析

    个推作为国内第三方推送市场的早期进入者,专注于为开发者提供高效稳定的推送服务,经过9年的积累和发展,服务了包括新浪.滴滴在内的数十万APP.由于我们推送业务对并发量.速度要求很高,为此,我们选择了高性 ...

  9. Redis大key的发现与删除方法全解析

    个推作为国内第三方推送市场的早期进入者,专注于为开发者提供高效稳定的推送服务,经过9年的积累和发展,服务了包括新浪.滴滴在内的数十万APP.由于我们推送业务对并发量.速度要求很高,为此,我们选择了高性 ...

随机推荐

  1. javascript 函数的4种调用模式

    1. 函数模式 // this 指向 window 全局对象 2. 方法模式 // this 指向调用这个方法的对象 3. 构造函数模式 // this 指向 new 新创建出来的实例 4. 上下文模 ...

  2. javascript 值类型和引用类型

    值类型 1. 值类型:string/number/boolean/undefined: 2. 存储:值类型的数据,存储的是数据本身的变量: 3. 赋值:直接将存储的数据复制一份进行赋值,两份数据在内存 ...

  3. Hbase记录-Hbase基础概念

    HBase是什么? HBase是建立在Hadoop文件系统之上的分布式面向列的数据库.它是一个开源项目,是横向扩展的. HBase是一个数据模型,类似于谷歌的大表设计,可以提供快速随机访问海量结构化数 ...

  4. 线程本地变量ThreadLocal (耗时工具)【原】

    线程本地变量类 package king; import java.util.ArrayList; import java.util.List; import java.util.Map; impor ...

  5. Git与GitHub学习笔记(四)合并远程分支

    在这里的前提: 1.你已经fork 源作者的项目到你自己的仓库了 2.git clone 自己仓库fork的项目,注意地址,这里是自己的账号下的地址,而不是源作者的项目地址哦 3.在本地修改代码,gi ...

  6. Prezento – 轻量、简单的 jQuery 幻灯片插件

    Prezento 是一个超级简单的 jQuery 幻灯片插件.可以让你网页以新颖的交互方式呈现.另外,Prezento 支持响应式设计,配置项也很灵活,可以根据你需要的效果配置. 您可能感兴趣的相关文 ...

  7. 调用write()写

    一.在POSIX中的定义 #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); 二.返回值 ( ...

  8. ettercap 模块使用

    Ettercap的过滤规则只能经过编译之后才能由-F参数载入到ettercap中使用. 编译过滤规则命令是:etterfilter filter.ecf -o filter.ef. 过滤规则的语法与C ...

  9. [CQOI2011]放棋子 (DP,数论)

    [CQOI2011]放棋子 \(solution:\) 看到这道题我们首先就应该想到有可能是DP和数论,因为题目已经很有特性了(首先题面是放棋子)(然后这一题方案数很多要取模)(而且这一题的数据范围很 ...

  10. mysql 查询优化~sql优化通用

    一 简介:今天我们来探讨下SQL语句的优化基础 二 基础规则: 一 通用: 1 避免索引字段使用函数     2 避免发生隐式转换     3 order by字段需要走索引,否则会发生filesor ...