Redis中关于Key的模糊查找

最近使用Redis优化项目功能,其中有一部分为模糊查询,找了很多帖子,也没有找到很好的解决方案和思路,最终皇天不负有心人啊,终于让我找到了!!!

感谢该帖作者:WalkerAlone  原文链接:http://blog.csdn.net/qq_28893679/article/details/53005057

可以通过Redis中keys命令进行获取key值,具体命令格式:keys pattern 

文中提到redis中允许模糊查询的有3个通配符,分别是:*,?,[]

其中:

*:通配任意多个字符

?:通配单个字符

[]:通配括号内的某一个字符

=========================================================================

在实际项目中有可能会使用spring集成redis的RedisTemplate进行操作,这样在注入模板时可能会出现模糊查询不好用的情况,是因为keys方法是存在于StringRedisTemplate子类中(父类-RedisTemplate)的

在spring配置时,一定要注意!!!

=========================================================================

实际操作中具体的思路:

1. 将要查询的条件当做key进行ZSet存储

2. 在获取时,调用StringRedisTemplate.keys(pattern),例:

1

2

3

4

5

publicSet keys(String pattern){

  returnstringRedisTemplate.keys("*"+ pattern + "*");

   // return stringRedisTemplate.keys("?" + pattern);

  // return stringRedisTemplate.keys("[" + pattern + "]");

}


ps:模糊查找适用于 String数据结构,对redis支持的其他结构(List、set等),没有 验证是否支持。


实践代码:

/**

* redis缓存操作类

*/

@Service

publicclassRedisCacheServiceimplementsInitializingBean{

privateValueOperations valueOperations;

@Autowired

privateStringRedisTemplate redisTemplate;

@SuppressWarnings("unchecked")

@Override

publicvoidafterPropertiesSet()throwsException{

RedisSerializer redisSerializer =newStringRedisSerializer();

valueOperations = redisTemplate.opsForValue();

}

/**

* 从缓存中获取资源信息

*@paramkey

*@return

*/

publicListgetCacheResource(String key){

Set<String> keys = redisTemplate.keys(key);

if(CollectionUtils.isEmpty(keys)) {

returnnewArrayList<>();

}

List resourceCacheBOList =newArrayList<>();

for(String accurateKey : keys) {

String cacheValue = valueOperations.get(accurateKey);

List<ResourceCacheBO> sub = JSONArray.parseArray(cacheValue, ResourceCacheBO.class);

resourceCacheBOList.addAll(sub);

}

returnresourceCacheBOList;

}


【key存在,而redisTemplate查找不到】

遇到问题:存在key:“A_091_JPFX”,但是用 模糊key:“A_*_JPFX”匹配时,却匹配不到;有资料说是编码问题,按下面方式解决:

原文链接:redisTemplate.keys(pattern)模糊查询找不到keys:https://blog.csdn.net/cutterwolf/article/details/77990112


在使用redisTemplate.keys查找keys时,发现明明相应的key是存在的,模糊查询就是查找不出来;原因有二:

1.确定你的查询字符串是否正确

2.就是的你key值有可能是乱码了就是遇到\xca\xed加上你key之类的乱码!例如:这里写图片描述

你需要重新定义key

@Bean

publicRedisTemplateredisTemplate(RedisConnectionFactory factory){

RedisTemplate redisTemplate =newRedisTemplate();

      redisTemplate.setConnectionFactory(factory); 

//key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误; 

//所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer 

//或者JdkSerializationRedisSerializer序列化方式; 

RedisSerializer redisSerializer =newStringRedisSerializer();//Long类型不可以会出现异常信息; 

    redisTemplate.setKeySerializer(redisSerializer); 

    redisTemplate.setHashKeySerializer(redisSerializer); 

returnredisTemplate;

    } 



完整代码:

packagecn.xxt.word.analysis.service;

importcn.xxt.ssm.commons.exception.BizException;

importcn.xxt.ssm.commons.json.JacksonJsonUtil;

importcn.xxt.word.analysis.pojo.bo.QuestCacheBO;

importcn.xxt.word.analysis.pojo.bo.ResourceCacheBO;

importcom.alibaba.fastjson.JSONArray;

importorg.springframework.beans.factory.InitializingBean;

importorg.springframework.beans.factory.annotation.Autowired;

importorg.springframework.data.redis.core.StringRedisTemplate;

importorg.springframework.data.redis.core.ValueOperations;

importorg.springframework.data.redis.serializer.RedisSerializer;

importorg.springframework.data.redis.serializer.StringRedisSerializer;

importorg.springframework.stereotype.Service;

importorg.springframework.util.CollectionUtils;

importorg.springframework.util.StringUtils;

importjava.util.ArrayList;

importjava.util.Collections;

importjava.util.List;

importjava.util.Set;

/**

* redis缓存操作类

*/

@Service

publicclassRedisCacheServiceimplementsInitializingBean{

privateValueOperations valueOperations;

@Autowired

privateStringRedisTemplate redisTemplate;

@SuppressWarnings("unchecked")

@Override

publicvoidafterPropertiesSet()throwsException{

RedisSerializer redisSerializer =newStringRedisSerializer();//Long类型不可以会出现异常信息;

redisTemplate.setKeySerializer(redisSerializer);

redisTemplate.setHashKeySerializer(redisSerializer);

valueOperations = redisTemplate.opsForValue();

}

/**

* 缓存资源

*@paramkey

*@paramresourceCacheBOList

*/

publicvoidcacheResource(String key, List<ResourceCacheBO> resourceCacheBOList){

// 参数校验

if(CollectionUtils.isEmpty(resourceCacheBOList)) {

thrownewBizException(1,"参数有误");

}

// 缓存

String resourceCacheValue = JacksonJsonUtil.objectToString(resourceCacheBOList);

valueOperations.set(key, resourceCacheValue);

}

/**

* 从缓存中获取资源信息

*@paramkey

*@return

*/

// TODO 待测试

publicListgetCacheResource(String key){

Set<String> keys = redisTemplate.keys(key);

if(CollectionUtils.isEmpty(keys)) {

returnnewArrayList<>();

}

List resourceCacheBOList =newArrayList<>();

for(String accurateKey : keys) {

String cacheValue = valueOperations.get(accurateKey);

List<ResourceCacheBO> sub = JSONArray.parseArray(cacheValue, ResourceCacheBO.class);

resourceCacheBOList.addAll(sub);

}

returnresourceCacheBOList;

}

/**

* 缓存 关键字的编码

*@paramkey

*@return

*/

publicvoidcacheKeyWordCode(String key, String code){

// 参数校验

if(StringUtils.isEmpty(key) || StringUtils.isEmpty(code)) {

thrownewBizException(1,"参数有误");

}

// 缓存

valueOperations.set(key, code);

}

/**

* 获取 关键字的编码

*@paramkey

*@return

*/

publicStringgetKeyWordCode(String key){

String keyWordCode = valueOperations.get(key);

if(StringUtils.isEmpty(keyWordCode)) {

returnnull;

}else{

returnkeyWordCode;

}

}

/**

* 批量获取 关键字的编码

*@paramkeys

*@return

*/

publicListbatchGetKeyWordCode(List<String> keys){

List<String> codes = valueOperations.multiGet(keys);

if(CollectionUtils.isEmpty(codes)) {

returnnewArrayList<>();

}else{

codes.removeAll(Collections.singleton(null));

returncodes;

}

}

}


【RedisTemplate和StringRedisTemplate的区别】

原文链接:https://blog.csdn.net/notsaltedfish/article/details/75948281


最近在开始在学习Redis以及如何在Java当中去使用Redis,Redis是什么我这里就不说了。

我主要想说的是Redis和Java当中Spring结合起来的时候,使用到的RedisTemplate和StringRedisTemplate

他们两者之间的区别,以及该怎么使用。

RedisTemplate看这个类的名字后缀是Template,如果了解过Spring如何连接关系型数据库的,大概不会难猜出这个类是做什么的 ,它跟JdbcTemplate一样封装了对Redis的一些常用的操作,当然StringRedisTemplate跟RedisTemplate功能类似那么肯定就会有人问,为什么会需要两个Template呢,一个不就够了吗?其实他们两者之间的区别主要在于他们使用的序列化类。

RedisTemplate使用的是 JdkSerializationRedisSerializer

StringRedisTemplate使用的是 StringRedisSerializer


RedisTemplate使用的序列类在在操作数据的时候,比如说存入数据会将数据先序列化成字节数组

然后在存入Redis数据库,这个时候打开Redis查看的时候,你会看到你的数据不是以可读的形式

展现的,而是以字节数组显示,类似下面

当然从Redis获取数据的时候也会默认将数据当做字节数组转化,这样就会导致一个问题,当需要获取的

数据不是以字节数组存在redis当中而是正常的可读的字符串的时候,比如说下面这种形式的数据

注:使用的软件是RedisDesktopManager

RedisTemplate就无法获取导数据,这个时候获取到的值就是NULL。这个时候StringRedisTempate就派上了用场


当Redis当中的数据值是以可读的形式显示出来的时候,只能使用StringRedisTemplate才能获取到里面的数据。

所以当你使用RedisTemplate获取不到数据的时候请检查一下是不是Redis里面的数据是可读形式而非字节数组


另外我在测试的时候即使把StringRedisTemplate的序列化类修改成RedisTemplate的JdkSerializationRedisSerializer

最后还是无法获取被序列化的对象数据,即使是没有转化为对象的字节数组,代码如下

@Test

publicvoidtestRedisSerializer(){

User u =newUser();

u.setName("java");

u.setSex("male");

redisTemplate.opsForHash().put("user:","1",u);

/*查看redisTemplate 的Serializer*/

System.out.println(redisTemplate.getKeySerializer());

System.out.println(redisTemplate.getValueSerializer());

/*查看StringRedisTemplate 的Serializer*/

System.out.println(stringRedisTemplate.getValueSerializer());

System.out.println(stringRedisTemplate.getValueSerializer());

/*将stringRedisTemplate序列化类设置成RedisTemplate的序列化类*/

stringRedisTemplate.setKeySerializer(newJdkSerializationRedisSerializer());

stringRedisTemplate.setValueSerializer(newJdkSerializationRedisSerializer());

/*即使在更换stringRedisTemplate的的Serializer和redisTemplate一致的

* JdkSerializationRedisSerializer

* 最后还是无法从redis中获取序列化的数据

* */

System.out.println(stringRedisTemplate.getValueSerializer());

System.out.println(stringRedisTemplate.getValueSerializer());

User user = (User) redisTemplate.opsForHash().get("user:","1");

User user2 = (User) stringRedisTemplate.opsForHash().get("user:","1");

System.out.println("dsd");

}

总结:

当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可,

但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345