Redis缓存穿透

 1、什么是缓存穿透?

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,下一次查询时,也会查询到数据库。

2、缓存穿透的解决办法

 (1)缓存空对象      (2)布隆过滤
缓存空对象:顾名思义,为了防止下一次查询不查询数据库,当发现查询redis和数据库都不存在                          数据时,可以存入一个value长度为0的字符串到redis中。                                            布隆过滤: 布隆过滤器其实采用的是哈希思想来解决这个问题,通过一个庞大的二进制数组,走                        哈希思想去判断当前这个要查询的这个数据是否存在,如果布隆过滤器判断存在,                          则放行,这个请求会去访问redis,哪怕此时redis中的数据过期了,但是数据库中一                       定存在这个数据,在数据库中查询出来这个数据后,再将其放入到redis中,假设布                         隆过滤器判断这个数据不存在,则直接返回

布隆过滤优点在于节约内存空间,存在误判,误判原因在于:布隆过滤器走的是哈希思想,只要哈希思想,就可能存在哈希冲突。

这里我就说以下思想,不实现布隆过滤了,挺复杂的。

3、优缺点

缓存空对象
   优点:实现简单,维护方便
   缺点:
             额外的内存消耗
             可能造成短期的不一致

布隆过滤
   优点:内存占用较少,没有多余key
   缺点:
             实现复杂
             存在误判可能

4、具体实现

例:根据id查询商铺类型。

//建表语句
CREATE TABLE `tb_shop_type`  (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类型名称',
  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图标',
  `sort` int(3) UNSIGNED NULL DEFAULT NULL COMMENT '顺序',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;

   流程图:

 代码实现:

    //缓存穿透
    public Result queryByType(Long id){
        //查询缓存
        String strJson = redisTemplate.opsForValue().get("cache_shop_type_id_"+id);
        //判断是否命中缓存
        //***命中,返回数据
        if(!StrUtil.isEmpty(strJson)){
            ShopType st = JSONUtil.toBean(strJson, ShopType.class);
            return Result.success(st);
        }

        //缓存缓存穿透后需要判断strJson,这里不能使用strJson.length() == 0 或者 strJson == "",
        //如果strJson=Null,可能是因为redis里没有数据,而不是查到了缓存击穿的数据
        if(strJson != null)
            return Result.error("无此商店类型ss");
        //***没命中
          //数据库查询
        ShopType st = mapper.queryById(id);
        if(st==null){
            //缓存穿透,添加 值为“”的数据
            stringRedisTemplate.opsForValue().set( "cache_shop_type_id_"+id,"",10, TimeUnit.MINUTES);
            return Result.error("无此商店类型");
        }
        //将数据加入缓存,有效期20分钟
        stringRedisTemplate.opsForValue().set("cache_shop_type_id_"+id,JSONUtil.toJsonStr(st),20L, TimeUnit.MINUTES);
        return Result.success(st);
    }
}

这是我的Result:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Integer code;//响应码,1 代表成功; 0 代表失败
    private String msg;  //响应信息 描述字符串
    private Object data; //返回的数据

    //增删改 成功响应
    public static Result success(){
        return new Result(1,"success",null);
    }
    //查询 成功响应
    public static Result success(Object data){
        return new Result(1,"success",data);
    }
    //失败响应
    public static Result error(String msg){
        return new Result(0,msg,null);
    }
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值