redis批量先查缓存再查数据库

java 复制代码
 /**
     *  批量查询缓存,若是缓存没有的数据再调用对应的方法查询数据,查询之后放入缓存
     * @param prefix 缓存前缀
     * @param params 缓存参数
     * @param column 缓存参数对应字段列名
     * @param dataBaseFunction 数据库查询方法
     * @return
     * @param <T> 查询参数
     * @param <R> 返回类型
     */
    public  <T,R> List<R> batchGetCacheData(String prefix, Collection<T> params, String column,
                                            Function<Set<T>,List<R>> dataBaseFunction, Class<R> clazz){
        // TODO 未大规模测试 谨慎使用
        //       先查redis
        Set<String> keys = params.stream().map(m -> {return prefix + m;}).collect(Collectors.toSet());
        List<String> cacheResultList = new ArrayList<>();
        List<List<T>> splitList = ListUtil.split((Collection<T>) keys, 500);
        for (List<T> ts : splitList) {
            cacheResultList.addAll(redisTemplate.executePipelined(new RedisCallback<String>() {
                @Override
                public String doInRedis(RedisConnection connection) throws DataAccessException {
                    for (T key : ts) {
                        connection.get(key.toString().getBytes());
                    }
                    return null;
                }
            }));
        }
        //过滤出没有获取到缓存的数据,去执行对应数据库查询
        Tuple2<Set<T>, List<R>> tuple2 = analysisCacheVal(params, cacheResultList, clazz);
        Set<T> queryKeys = tuple2.getFirst();
        List<R> result = tuple2.getSecond();
        if(!CollectionUtils.isEmpty(result) && result.size() == params.size()){
            return result;
        }
        List<R> dataBaseResult = getDataBaseFunction(prefix, queryKeys, dataBaseFunction, column);
        result.addAll(dataBaseResult);
        return result;
    }

    private static <T,R> Tuple2<Set<T>, List<R>> analysisCacheVal (Collection<T> params, List<String> cacheResultList, Class<R> clazz) {
        Set<T> queryKeys = new HashSet<>();
        List<R> result = new ArrayList<>();
        T[] paramsObj = (T[]) params.toArray();
        for (int i = 0; i< params.size(); i++) {
            String cacheR = cacheResultList.get(i);
            if (Objects.isNull(cacheR)) {
                queryKeys.add(paramsObj[i]);
            } else {
                result.add(JSON.parseObject(cacheR, clazz));
            }
        }
        return new Tuple2<>(queryKeys, result);
    }

    private <T,R> List<R> getDataBaseFunction (String prefix, Set<T> queryKeys, Function<Set<T>,List<R>> dataBaseFunction, String column) {
        List<R> dataBaseResult = dataBaseFunction.apply(queryKeys);
        if(!CollectionUtils.isEmpty(dataBaseResult)){
            for (R r : dataBaseResult) {
                Object obj = getProperty(r, column);
                if (Objects.nonNull(obj)) {
                    redisTemplate.opsForValue().set(prefix + obj.toString(), JSON.toJSONString(r), 1, TimeUnit.MINUTES);
                }
            }
        }
        return dataBaseResult;
    }


    public static <R> Object getProperty(R object, String column) {
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.getName().equals(column)) {
                try {
                    field.setAccessible(true);
                    return field.get(object);
                } catch (IllegalAccessException e) {
                    log.error("RedisUtil getProperty error {}", e);
                    return null;
                }
            }
        }
        return null;
    }

使用方式

redisUtil.batchGetCacheData("country:", ids, "id", v -> baseMapper.getByIds(ids), 查询对象.class);

java 复制代码
public class ListUtil {
    public static final int DEFAULT_LIMIT = 500;
    public static final int LIMIT1000 = 1000;

    public static <T> List<List<T>> split(Collection<T> collection) {
        return split(collection, DEFAULT_LIMIT);
    }

    public static <T> List<List<T>> split(Collection<T> collection, int size) {
        if (collection == null || collection.isEmpty()) {
            return Collections.emptyList();
        }
        List<T> list = new ArrayList<>(collection);
        final int listSize = list.size();
        final List<List<T>> result = new ArrayList<>(listSize / size + 1);
        int offset = 0;
        for (int toIdx = size; toIdx <= listSize; offset = toIdx, toIdx += size) {
            result.add(list.subList(offset, toIdx));
        }
        if (offset < listSize) {
            result.add(list.subList(offset, listSize));
        }
        return result;
    }

}
相关推荐
Lhappy嘻嘻3 小时前
Java IO|File 文件操作 + 字节流 / 字符流完整笔记 + 递归删除文件实战
java·笔记·php
伊玛目的门徒3 小时前
试用leetcode之典中典 二数之和问题
java·算法·leetcode
ffqws_3 小时前
Redis 分布式锁:基于 Redisson 的实现与面试高频问答
redis·分布式·面试
AI-好学者4 小时前
阶段一-图数据库基础与PropertyGraph模型
数据库·rag·knowledge graph·graphrag
其实防守也摸鱼6 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚6 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
龙仔7256 小时前
SQL Server 创建只读账号完整操作(分两种场景:SSMS图形界面 + T-SQL脚本)
数据库·sql·oracle
霁月的小屋6 小时前
生产环境中的事务实践——银行系统上线记(四)
数据库
Database_Cool_7 小时前
AI 应用数据底座首选:阿里云 PolarDB 为大模型 RAG 提供一体化支撑
数据库·阿里云
玖玥拾7 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#