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;
        }
    }
    
    
  • 相关阅读:
    积水路面Wet Road Materials 2.3
    门控时钟问题
    饮料机问题
    Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)
    Educational Codeforces Round 82 (Rated for Div. 2)部分题解
    Educational Codeforces Round 86 (Rated for Div. 2)部分题解
    Grakn Forces 2020部分题解
    2020 年百度之星·程序设计大赛
    POJ Nearest Common Ancestors (RMQ+树上dfs序求LCA)
    算法竞赛进阶指南 聚会 (LCA)
  • 原文地址:https://www.cnblogs.com/ingxx/p/13267053.html
Copyright © 2011-2022 走看看