解决Redis在高并发时,缓存穿透

1.直接在方法上加synchronized

    public synchronized User getUserById(Integer id) {
        // 设置redis的key按照String进行序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 查询redis缓存中是否存有数据
        User user = (User) redisTemplate.opsForValue().get("userKey-" + id);

        // redis缓存中没有该学生信息
        if (user == null) {
            // 从数据库中查询,在存储到redis缓存中
            user = userMapper.selectByPrimaryKey(id); 
            redisTemplate.opsForValue().set("userKey-"+ id, user);
            System.out.println("查询了数据库。。。");
        } else {
            System.out.println("查询了缓存。。。。");
        }
        return user;
    }

以上方法的弊端

该方法将每次调用getUserById方法的用户都进行加锁,这意味着,每次有且只能有一个用户进行查询缓存和查询数据库两个操作之一。

理想状态

当十个线程进来调用时,都可以查询redis缓存,让一个进来的线程去查询数据库,其他线程等待,该线程执行完后,其他九个线程再次执行查询缓存。

2.双重检查锁

    @Override
    public User getUserById(Integer id) {
        // 设置redis的key按照String进行序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 查询redis缓存中是否存有数据
        User user = (User) redisTemplate.opsForValue().get("userKey-" + id);

        // redis缓存中没有该学生信息
        if (user == null) {
            
            // 从数据库中查询,在存储到redis缓存中
            synchronized (this) {
                // 再查询一次redis缓存中是否存有该user数据
                user =  (User) redisTemplate.opsForValue().get("userKey-" + id);
                
                //依旧没有数据,则说明是第一次,进行查询数据库
                if(user == null) {
                    user = userMapper.selectByPrimaryKey(id);
                    redisTemplate.opsForValue().set("userKey-" + id, user);
                    System.out.println("查询了数据库。。。");
                }
            }
        } else {
            System.out.println("查询了缓存。。。。");
        }
        return user;
    }

以上代码解读

该方式,当第一波并发进行访问时,比如10个线程,10个查询redis缓存中,发现没有缓存。这时,user为null。在synchronized代码块中,一次只能执行一个线程。第一个线程获得锁时,发现redis缓存中还是没有数据,则去查询数据库,将查询的数据存储在redis缓存中。其他线程等啊等啊等。第一个线程终于结束了。其他九个线程再获得锁时,发现线程中有数据了,老子不干了。就可以大大的减少一个一个线程的执行了。

使用第二种方式比较适合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值