最近使用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:“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是更好的选择。