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;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM