zoukankan      html  css  js  c++  java
  • Redis批量查询模板

    场景

    在开发的时候经常会遇到批量取缓存的问题,例如查询商品信息

    1. 传入一个商品Id列表,查询Redis数据存在则放入返回列表
    2. 不存在的数据查找数据库,并放入Redis
    3. 上面两步数据整合返回
      伪代码为
    list.ForEach(str->{
    	dto = redis.get(str);
    		if(dto != null){
    		resultList.add(dto);
    	}else{
    		mustQuerySQL.add(str);
    	}
    })
    if(CollectionUtils.isNotEmpty(mustQuerySQL)){
    	querysqlList = querySQL(mustQuerySQL);
    	querySqlList.ForEach(dto->{
    		redis.put(dto);	
    		resultList.add(dto);
    	}
    })
    return resultList;
    

    问题是在项目中经常使用这样的模式,有什么办法可以简化步骤呢?

    模板方法模式

    模板方法模型是一种行为设计模型。模板方法是一个定义在父类别的方法,在模板方法中会呼叫多个定义在父类别的其他方法,而这些方法有可能只是抽象方法并没有实作,模板方法仅决定这些抽象方法的执行顺序,这些抽象方法的实作由子类别负责,并且子类别不允许覆写模板方法。
    我们可以使用模板方法模式,具体的从Redis中获取数据以及SQL中获取数据和SQL中数据放入Redis让子类进行实现。

    实现

    代码如下:

    public abstract class RedisUtil<T>  {
    
        public final List<T> getList(List<String> list){
            List<T> resultList = new ArrayList<>();
            List<String> mustQuery = new ArrayList<>();
            list.forEach(str->{
                T o = queryForRedis(str);
                if(o != null){
                    resultList.add(o);
                }else {
                    mustQuery.add(str);
                }
            });
            if(CollectionUtils.isNotEmpty(mustQuery)) {
                List<T> sql = queryForSQL(mustQuery);
                sql.forEach(dto->{
                    setForRedis(dto);
                    resultList.add(dto);
                });
            }
            return resultList;
        }
    
        protected abstract T queryForRedis(String str);
    
        protected abstract List<T> queryForSQL(List<String> list);
    
        protected abstract void setForRedis(T t);
    }
    

    子类只需要使用匿名类即可实现,但是这样在代码中会有这样的代码

    RedisUtil<String> redisUtil = new RedisUtil<String>() {
                @Override
                protected String queryForRedis(String str) {
                    return null;
                }
    
                @Override
                protected List<String> queryForSQL(List<String> list) {
                    return null;
                }
    
                @Override
                protected void setForRedis(String s) {
    
                }
            };
    

    占据大量的代码段,看起来并不优雅,如何优雅的实现呢?

    优化

    上面使用了匿名类,但是这样占据代码段,当然可以新建一个实体类进行实现,但是总归是不太优雅。
    我们可以使用JDK8中提供的函数式接口实现

    public class RedisUtil  {
        public static <T> List<T> getList(List<String> list, Function<String,T> queryRedis, Function<List<String>,List<T>> querySQL, Consumer<T> setRedis){
            List<T> resultList = new ArrayList<>();
            List<String> mustQuery = new ArrayList<>();
            list.forEach(str->{
                T o = queryRedis.apply(str);
                if(o != null){
                    resultList.add(o);
                }else {
                    mustQuery.add(str);
                }
            });
            if(CollectionUtils.isNotEmpty(mustQuery)) {
                List<T> sql = querySQL.apply(mustQuery);
                sql.forEach(dto->{
                    setRedis.accept(dto);
                    resultList.add(dto);
                });
            }
            return resultList;
        }
    }
    
    
  • 相关阅读:
    洛谷P1023 税收与补贴问题
    洛谷P2680 运输计划
    2014-11-3 NOIP模拟赛3
    一行Python代码就可以玩一些童年小游戏
    NuGet(微软.NET开发平台的软件包管理工具)在VisualStudio中的安装的使用
    Winform中实现序列化指定类型的对象到指定的Xml文件和从指定的Xml文件中反序列化指定类型的对象
    Electron中打开和关闭子窗口以及子窗口向父窗口传值
    Electron中实现通过webview实现内嵌网页并嵌入css样式和js脚本等
    Electron中实现拖拽文件进div中通过File对象获取文件的路径和内容
    Electron中通过process进程对象的api获取CPU、系统位数、环境变量等相关信息
  • 原文地址:https://www.cnblogs.com/ingxx/p/13267053.html
Copyright © 2011-2022 走看看