解决缓存穿透和击穿自用工具类

本文介绍了如何将任意对象转化为JSON字符串存储于缓存,实现逻辑过期防止缓存穿透,以及使用线程池和互斥锁处理缓存击穿问题。重点展示了在Java应用中使用Redis进行高效缓存管理的方法。
摘要由CSDN通过智能技术生成
1、将任意对象都可以转换为json字符串形式存入缓存
public void set(String key, Object value, Long time, TimeUnit unit){
        // 需要将任意类型的对象转换为json字符串
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit);
    }
2、增加新一列:逻辑过期时间
public void setWithLogicalExpiredTime(String key, Object value, Long time, TimeUnit unit){
        RedisData redisData = new RedisData();
        redisData.setData(value);
        redisData.setExpiredTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
        stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(redisData));
    }
3、缓存穿透,参数中需要自己编写查询的函数
public <R,ID> R queryWithPassThrough(String prefix, ID id, Class<R> type, Function<ID,R> dbCallback,Long time,TimeUnit unit){
        String key = prefix + id;
        // 从redis中进行查询
        String info = stringRedisTemplate.opsForValue().get(key);
        // 查询到了直接返回
        if(StrUtil.isNotBlank(info)){
            return JSONUtil.toBean(info, type);
        }
        // 判断是否为null 或 空
        if (info != null){
            return null;
        }
        // 未查询到向数据库进行查询 交给调用者去编写
        //Shop shop = getById(id);
        R res = dbCallback.apply(id);
        // 数据库若也未查询到 返回404 防缓存穿透加入一个空值
        if(res == null){
            stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
            return null;
        }
        // 若查询到了将数据写入缓存
        // 增加一个超时剔除
        this.set(key,res,time,unit);
        // 返回查询到的结果
        return res;
    }
4、逻辑过期的形式解决缓存击穿,里面包含了线程池,获取互斥锁,释放锁等方法
private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
    public <R,ID> R queryWithLogicalExpire(String prefix, ID id, Class<R> type, Function<ID,R> dbCallback,Long time,TimeUnit unit){
        String key = prefix + id;
        // 从redis中进行查询
        String info = stringRedisTemplate.opsForValue().get(key);
        // 没有查询到返回空
        if(StrUtil.isBlank(info)){
            R res = JSONUtil.toBean(info, type);
            return null;
        }
        // 查询到获取字段 检查过期时间
        // 先把json字符串反序列化为对象
        RedisData redisData = JSONUtil.toBean(info, RedisData.class);
        JSONObject data = (JSONObject) redisData.getData();
        R res = JSONUtil.toBean(data, type);
        LocalDateTime expiredTime = redisData.getExpiredTime();
        // 没过期返回商品信息
        if(expiredTime.isAfter(LocalDateTime.now())){
            return res;
        }
        // 过期了尝试获取互斥锁
        // 缓存重建
        String lockKey = LOCK_SHOP_KEY+id;
        boolean triedLock = tryLock(lockKey);
        // 获取到了 开启新线程
        if(triedLock){
            // 开启新线程
            CACHE_REBUILD_EXECUTOR.submit(() -> {
                R r = dbCallback.apply(id);
                this.setWithLogicalExpiredTime(key,r,time,unit);
                unlock(lockKey);
            });
        }

        // 没获取到 直接返回旧信息
        return res;
    }

    // 加互斥锁
    private boolean tryLock(String key){
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", LOCK_SHOP_TTL, TimeUnit.SECONDS);
        return BooleanUtil.isTrue(flag);
    }
    // 释放锁
    private void unlock(String key){
        stringRedisTemplate.delete(key);
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值