Redis模糊查询以及分页

今天在进行项目的时候需要Redis实现一个功能

需求:Redis hash类型模糊查询,同时对结果进行分页

首先是Redis hash类型模糊查询

//Cusor中存储的是查询key对应的Map
Cursor<Map.Entry<String,String>> cursor = redisTemplate
    .opsForHash()
    .scan("zhDicGoods", ScanOptions.scanOptions()       //绑定模糊查询的hash的key
          .match(name+"*")                                 //模糊查询规则
          .count(10000).build());

其中关于match参数pattern

*:通配任意多个字符

?:通配单个字符

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

再此遇到了一个问题,就是在模糊查询的时候**“查询内容+*”**可能查询不到,原因是redis默认的导入数据的时候可能存在乱码的问题

就是遇到\xca\xed加上你key之类的乱码!

你需要重新定义你导入key的内容

在启动类中加入一个Bean

@Bean  
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {  
       RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();  
       redisTemplate.setConnectionFactory(factory);  
 
       //key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误;  
       //所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer  
       //或者JdkSerializationRedisSerializer序列化方式;  
     RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;  
     redisTemplate.setKeySerializer(redisSerializer);  
     redisTemplate.setHashKeySerializer(redisSerializer);  
 
       return redisTemplate;  

以上解决了redis模糊查询的问题,接下来就是模糊查询的结果返回分页

此处引用网上的资料,我会在末尾标注出来

利用ZSET及HASH结构存储数据实现redis分页。

1.  首先利用ZSET将表A中的id以value形式进行存储,以及利用ZSET中score进行排序处理;
2.  将表A中数据以HASH结构进行存储,id作为HASH中key;
3.  利用redis中的zRangeByScore进行ZSET分页取出id列表,然后即可取出HASH中分页后的数据。

先创建一个pageUtil

@Component
public class PageUtil {
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 存放单个hash缓存
     * @param key 键
     * @param hkey 键
     * @param value 值
     * @return
     */
    public boolean hput(String key, String hkey, Object value) {
        try {
            redisTemplate.opsForHash().put(key, hkey, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 分页存取数据
     * @param key  hash存取的key
     * @param hkey hash存取的hkey
     * @param score 指定字段排序
     * @param value
     * @return
     */
    public boolean setPage(String key, String hkey, double score, String value){
        boolean result = false;
        try {
            result=redisTemplate.opsForZSet().add(key + ":page", hkey, score);
            //result = hput(key, hkey, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //设置辅助分页的过期时间
        redisTemplate.expire(key+":page",1800000 , TimeUnit.MILLISECONDS);
        //redisTemplate.expire(key,60000 , TimeUnit.MILLISECONDS);
        return result;
    }

    /**
     * 分页取出 hash中hkey值
     * @param key
     * @param offset
     * @param count
     * @return
     */
    public  Set<String> getPage(String key, int offset, int count){
        Set<String> result = null;
        try {
            result = redisTemplate.opsForZSet().rangeByScore(key+":page", 1, 100000, (offset-1)*count, count);//1 100000代表score的排序氛围值,即从1-100000的范围
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 计算key值对应的数量
     * @param key
     * @return
     */
    public Integer getSize(String key){
        Integer num = 0;
        try {
            Long size = redisTemplate.opsForZSet().zCard(key+":page");
            return size.intValue();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return num;
    }
}

此处offset就是页码, count就是每页显示的条数

调用就是在存储hash的时候存储一个对应的分页数据

/**
     * 生成辅助分页
     * @param cursor
     * @param name:会在pageutil中自动加上:page
     */
private void setPage(Cursor<Map.Entry<String,String>> cursor,String name,String tableName){
    //setPage初始化值,zset的sort值
    int i = 1;
    //遍历模糊查询结果,将模糊查询的结果生成分页数据,用zset存储模糊查询的数据排序
    //存储名称是查询name+:page,值是hash类型的key
    while (cursor.hasNext()){
        Map.Entry<String,String> result= cursor.next();
        //获取key
        String key = result.getKey();
        //获取value
        String value = result.getValue();
        //存储对应的辅助分页数据
        pageUtil.setPage(tableName+name,key,i,null);
        i++;

    }
}

然后就是查询数据的时候不从hash中查询,从zset中查询到hkey,然后在查询hash类型

/**
     * 获取分页的总数据,并且加入到map中
     * @param name
     * @param currentPage
     * @param count
     * @param resultMap
     * @param result
     */
private void getPageResult(String name,int currentPage, int count,Map resultMap,ArrayList result,String tableName,T t){

    //得到分页数据总条数
    Integer totalNumber = pageUtil.getSize(tableName+name);
    //得到对应分页的key数组
    Set<String> keyPages = pageUtil.getPage(tableName+name, currentPage, count);
    //遍历循环查询对应cout对应的数据,同时转为对象输入到List
    count =keyPages.size();
    for (String keyPage : keyPages) {
        //根据zset的key查询hash对应的数据
        String JSONObject = (String) redisTemplate.boundHashOps(tableName).get(keyPage);
        //转为对应的实体类
        T Object = (T) JSON.parseObject(JSONObject, (Type) t);
        result.add(Object);
    }
    //返回总页数
    Integer totalPage;
    if(totalNumber<=count){
        totalPage=1;
    }else {
        totalPage =totalNumber/10+1;
    }

    //加入返回实体类结果,总条数,起始页数,总条数
    resultMap.put("result",result);
    resultMap.put("totalNumber",totalNumber);
    resultMap.put("currentPage",currentPage);
    resultMap.put("count",count);
    resultMap.put("totalPage",totalPage);
}

模糊查询以及分页我设置了一个工具类,总的是

@Component
public class RedisFurryAndPageQueryUtil<T> {
    //插入辅助分页
    @Autowired
    private PageUtil pageUtil;
    //注入redis模板工具
    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 根据条件进行模糊查询查询并返回分页结果
     * @param name
     * @param currentPage
     * @param count
     * @return
     */
    public Map<String,Object> find(String name, int currentPage, int count,String tableName,T t) {
        //将传入的参数变为小写
        name = StringUtils.lowerCase(name);
        //map用来存储查询到的结果以及分页的总数据
        Map<String,Object> map = new HashMap<>();
        //用来存储查询到的ZhDicGoods
        ArrayList<ZhDicGoods> result = new ArrayList<>();
        //定义pageName用来查看redis中是否存在对应的辅助分页key-value
        String pageName = tableName+name + ":page";
        //是否存在对应的辅助分页辅助分页key-value
        Boolean ifExist = redisTemplate.hasKey(pageName);
        //如果不存在,生成辅助分页,同时查询
        if(!ifExist){
            try {
                //如果传入参数为空则查询所有
                if(name==null||"".equals(name)){
                    //模糊查询返回结果
                    //Cusor中存储的是查询key对应的Map
                    Cursor<Map.Entry<String,String>> cursor = redisTemplate
                            .opsForHash()
                            .scan(tableName, ScanOptions.scanOptions()       //绑定模糊查询的hash的key
                                    .match("*")                                      //模糊查询规则
                                    .count(1000).build());
                }
                //模糊查询返回结果
                //Cusor中存储的是查询key对应的Map
                Cursor<Map.Entry<String,String>> cursor = redisTemplate
                        .opsForHash()
                        .scan(tableName, ScanOptions.scanOptions()       //绑定模糊查询的hash的key
                                .match(name+"*")                                 //模糊查询规则
                                .count(10000).build());
                //生成分页key-value
                setPage(cursor,name,tableName);
                //生成查询结果并且放入map中
                getPageResult(name,currentPage,count,map,result,tableName,t);
                cursor.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            //有辅助分页key-value,直接查询结果放入map中
            getPageResult(name,currentPage,count,map,result,tableName,t);
        }
        //返回result
        return map;

    }


    /**
     * 生成辅助分页
     * @param cursor
     * @param name:会在pageutil中自动加上:page
     */
    private void setPage(Cursor<Map.Entry<String,String>> cursor,String name,String tableName){
        //setPage初始化值,zset的sort值
        int i = 1;
        //遍历模糊查询结果,将模糊查询的结果生成分页数据,用zset存储模糊查询的数据排序
        //存储名称是查询name+:page,值是hash类型的key
        while (cursor.hasNext()){
            Map.Entry<String,String> result= cursor.next();
            //获取key
            String key = result.getKey();
            //获取value
            String value = result.getValue();
            //存储对应的辅助分页数据
            pageUtil.setPage(tableName+name,key,i,null);
            i++;

        }
    }


    /**
     * 获取分页的总数据,并且加入到map中
     * @param name
     * @param currentPage
     * @param count
     * @param resultMap
     * @param result
     */
    private void getPageResult(String name,int currentPage, int count,Map resultMap,ArrayList result,String tableName,T t){

        //得到分页数据总条数
        Integer totalNumber = pageUtil.getSize(tableName+name);
        //得到对应分页的key数组
        Set<String> keyPages = pageUtil.getPage(tableName+name, currentPage, count);
        //遍历循环查询对应cout对应的数据,同时转为对象输入到List
        count =keyPages.size();
        for (String keyPage : keyPages) {
            //根据zset的key查询hash对应的数据
            String JSONObject = (String) redisTemplate.boundHashOps(tableName).get(keyPage);
            //转为对应的实体类
            T Object = (T) JSON.parseObject(JSONObject, (Type) t);
            result.add(Object);
        }
        //返回总页数
        Integer totalPage;
        if(totalNumber<=count){
            totalPage=1;
        }else {
            totalPage =totalNumber/10+1;
        }

        //加入返回实体类结果,总条数,起始页数,总条数
        resultMap.put("result",result);
        resultMap.put("totalNumber",totalNumber);
        resultMap.put("currentPage",currentPage);
        resultMap.put("count",count);
        resultMap.put("totalPage",totalPage);
    }

}

以上就是此次工作的整体步骤

查看的文档还有博客有

spring中redisTemplate实现redis分页

https://segmentfault.com/a/1190000020866225

redis 模糊查询

https://blog.csdn.net/zhaipengfei1231/article/details/80819454?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.edu_weight

scan实现模糊查询redis数据

https://blog.csdn.net/yuan_sun/article/details/102663986?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.edu_weight

Springdataredis Api文档

https://docs.spring.io/spring-data/redis/docs/2.2.4.RELEASE/api/

一些小知识

StringRedisTemplate/RedisTemplate设置过期时间

https://blog.csdn.net/qq_35192741/article/details/91448395

//redistemplate是否包含key
public Boolean hasKey(K key)
//子类继承父类的文档注释
ctrl+O  弹出的窗口下面把 勾下 JavaDoc 就可以了
  • 11
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值