Redis解决缓存击穿和缓存穿透的工具类

@Data
public class RedisData {
    private LocalDateTime expireTime;
    private Object data;
}
package com.martin.utils;/*
 * @Author Martin·Antonio
 * @Description TODO
 * @DateTime 2022/11/18 20:02
 * */

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@Component
public class CacheClient {

    private final StringRedisTemplate template;


    public CacheClient(StringRedisTemplate template) {
        this.template = template;
    }

    public void set(String key, Object value, Long time, TimeUnit unit){
        template.opsForValue().set(key, JSONUtil.toJsonStr(value),time,unit);
    }

    public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit){
        //设置逻辑过期
        RedisData redisData = new RedisData();
        redisData.setData(value);
        redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
        //写入redis
        template.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
    }

    private boolean tryLock(String key) {
        Boolean flag = template.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
        return BooleanUtil.isTrue(flag);
    }

    private void unlock(String key) {
        template.delete(key);
    }

    //缓存穿透
    public <R,ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID,R> dbFallBack, Long time, TimeUnit unit) {
        String key = keyPrefix + id;
        String lockKey = "lock:shop:" + id;
        String json = template.opsForValue().get(key);
        //2.判断是否存在
        if (StrUtil.isNotBlank(json)) {
            return JSONUtil.toBean(json,type);
        }
        if (json != null){
            return null;
        }
        R r = dbFallBack.apply(id);
        if (r == null) {
            template.opsForValue().set(key, JSONUtil.toJsonStr(r), time,unit);
            return r;
        }
        this.set(key, JSONUtil.toJsonStr(r), time,unit);
        return r;
    }

    private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);


    public <R,ID> R  logicExpire(String keyPrefix, ID id, Class<R> type, Function<ID,R> dbFallBack, Long time, TimeUnit unit) {

        String key = keyPrefix + id;
        String lockKey = "lock:shop:" + id;

        String json = template.opsForValue().get(key);
        //2.判断是否存在
        if (StrUtil.isBlank(json)) {
            return null;
        }
        //3.命中
        RedisData redisData = JSONUtil.toBean(json, RedisData.class);
        R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);
        LocalDateTime expireTime = redisData.getExpireTime();

        //4.判断是否过期
        if (expireTime.isAfter(LocalDateTime.now())) {
            //4.1未过期直接返回
            return r;
        }
        //4.2已过期,需要缓存重建
        boolean isLock = tryLock(lockKey);
        if (isLock) {
            //5.获取互斥锁
            CACHE_REBUILD_EXECUTOR.submit(() -> {
                //6.缓存重建
                try {
                    R apply = dbFallBack.apply(id);
                    this.setWithLogicalExpire(key, JSONUtil.toJsonStr(r), time,unit);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    //7.释放锁
                    unlock(lockKey);
                }
            });

        }
        return r;
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值