栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

关于redis解决缓存穿透和缓存击穿问题(java)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

关于redis解决缓存穿透和缓存击穿问题(java)

package com.gao.redisdemo.utils;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.cglib.core.internal.Function;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


@Component
@SuppressWarnings("all")
public class CacheClient {
    @Resource
    StringRedisTemplate stringRedisTemplate;

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

    
    public void setWithLogicExpire(String key, Object value, Long time, TimeUnit timeUnit) {
        //设置过期时间
        RedisData redisData = new RedisData();
        redisData.setValue(value);
        redisData.setLogicExpireTime(LocalDateTime.now().plusSeconds(timeUnit.toSeconds(time)));
        //写入redis
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
    }

    
    public  R queryWithPassThrough(String prefix, ID id, Class type, Function dbMethod, Long time, TimeUnit timeUnit) {
        String cacheKey = prefix + id;
        //根据id查询redis中是否有缓存值
        String json = stringRedisTemplate.opsForValue().get(cacheKey);
        //判断是否存在,只有"abc"才为true
        if (StringUtils.isNotBlank(json)) {
            return JSON.parseObject(json, type);
        }
        //判断是否为null,不是则为“”,空字符窜情况
        if (json != null) {
            return null;
        }
        //redis缓存中没有相关值,走查询书库
        R r = dbMethod.apply(id);
        //如果r不存在,则缓存“”进入redis
        if (r == null) {
            stringRedisTemplate.opsForValue().set(cacheKey, "", time, TimeUnit.MINUTES);
            return null;
        }
        //存在就存入相关信息进入redis
        this.set(cacheKey, r, time, timeUnit);
        return r;
    }


    
    //创建线程池
    private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);

    public  R queryWithLogicExpire(String prefix, ID id, Class type, Function dbMethod, Long time, TimeUnit timeUnit) {
        String cacheKey = prefix + id;
        //根据id查询redis中是否有缓存值
        String json = stringRedisTemplate.opsForValue().get(cacheKey);
        //判断是否存在
        if (StringUtils.isBlank(json)) {
            return null;
        }
        //命中,把json转化为相应Bean对象
        RedisData redisData = JSONUtil.toBean(json, RedisData.class);
        R r = JSONUtil.toBean((JSONObject) redisData.getValue(), type);
        LocalDateTime logicExpireTime = redisData.getLogicExpireTime();
        //判断是否过期,未过期直接返回信息
        if (logicExpireTime.isAfter(LocalDateTime.now())){
            return r;
        }
        //已经过期,缓存重建
        String localKey = "lock:" + prefix + id;
        //获取到互斥锁
        Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(localKey, "1", 10, TimeUnit.SECONDS);
        if (BooleanUtil.isTrue(aBoolean)){
          CACHE_REBUILD_EXECUTOR.submit(()->{
              try {
                  //查询数据库
                  R result = dbMethod.apply(id);
                  //写入缓存
                  this.setWithLogicExpire(cacheKey,result,time,timeUnit);
              } catch (Exception e) {
                  e.printStackTrace();
              }finally {
                  //释放互斥锁
                  stringRedisTemplate.delete(localKey);
              }
          });
        }
        return r;
    }

    
    @Data
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    static
    class RedisData {
        private Object value;
        private LocalDateTime logicExpireTime;
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/844663.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号