zoukankan      html  css  js  c++  java
  • Java Redis缓存穿透/缓存雪崩/缓存击穿,Redis分布式锁实现秒杀,限购等

    package com.example.redisdistlock.controller;
    
    import com.example.redisdistlock.util.RedisUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    public class CacheController {
    
        @Autowired
        private StringRedisTemplate stringRedisTemplate = null;
    
        @Autowired
        private RedisUtil redisUtil = null;
    
        /**
         * ****************************** 缓存穿透 ******************************
         * 缓存穿透,是指查询一个数据库一定不存在的数据。
         * 正常的使用缓存流程大致是,数据查询先进行缓存查询,
         * 如果key不存在或者key已经过期,再对数据库进行查询,
         * 并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。
         * 灾难现场:想象一下这个情况,如果传入的参数为-1,会是怎么样?这个-1,就是一定不存在的对象。就会每次都去查询数据库,
         *          而每次查询都是空,每次又都不会进行缓存。假如有恶意攻击,就可以利用这个漏洞,对数据库造成压力,甚至压垮数据库。
         * 解决方案:如果从数据库查询的对象为空,也放入缓存,只是设定的缓存过期时间较短,比如设置为60秒。
         */
    
    
        /**
         * ****************************** 缓存雪崩 ******************************
         * 是指在某一个时间段,缓存集中过期失效。此刻无数的请求直接绕开缓存,直接请求数据库。
         * 灾难现场:比如天猫双11,马上就要到双11零点,很快就会迎来一波抢购,这波商品在23点集中的放入了缓存,假设缓存一个小时。
         * 那么到了凌晨24点的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。
         * 对数据库造成压力,甚至压垮数据库。
         */
    
    
        /**
         * ****************************** 缓存击穿 ******************************
         * 是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
         * 灾难现场:比如某个爆款商品(这种爆款很难对数据库服务器造成压垮性的压力。达到这个级别的公司没有几家的。)但我们也要做好防护方案
         * 解决方案:对爆款商品都是早早的做好了准备,让缓存永不过期。即便某些商品自己发酵成了爆款,也是直接设为永不过期。
         */
    
        public  Object cacheBreakDown(){
            Map<String, Object> map = new HashMap<String, Object>();
            try {
                Object zhangsan = redisUtil.get("zhangsan");
                //System.out.println("zhangsan" + zhangsan);
    
                /* 使用双重验证锁解决高并发环境下的缓存穿透问题 */
                if (StringUtils.isEmpty(zhangsan)) { // 第一重验证
                    synchronized (this) {
                        zhangsan = redisUtil.get("zhangsan");
                        if (StringUtils.isEmpty(zhangsan)) { // 第二重验证
                            System.out.println("查询数据库............");
                            // 缓存为空,则查询数据库将相关数据存储到redis中
                            redisUtil.set("zhangsan", "张三",10); //10秒后过期
                        } else {
                            System.out.println("2 查询缓存............");
                        }
                    }
                } else {
                    System.out.println("1 查询缓存............");
                }
    
                map.put("success", true);
    
                ////entity实体类
                //User user = new User();
                //user.setUserId(1000);
                //user.setUserName("张三");
                //user.setAddress("深圳市南山区");
                //user.setMobile("13988886666");
                //redisUtil.set("userInfo", user.toString(), 10);  //10秒后过期自动删除
                ////获取显示
                //String str = String.valueOf(redisUtil.get("userInfo"));
                //JSONObject jsonObj = new JSONObject(str);
                //map.put("userInfo", jsonObj.get("userId"));
            } catch (Exception e) {
                map.put("success", false);
                e.printStackTrace();
            } finally {
            }
            return map;
        }
    }
    
        /**
         * Redis分布式并发锁(针对业务场景:库存超卖  秒杀  限购等)
         *
         * @return
         */
        @RequestMapping("/reductstore")
        @ResponseBody  //直接输出字符串
        public String ReductStore() {
            System.out.println("访问接口");
            String lockKey = "lock";
    
            // setnx   redisson
            RLock lock = redissonClient.getLock(lockKey);
            try {
    
                int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));     lock.lock();
                if (stock > 0) {
                    //业务逻辑减少库存
                    stringRedisTemplate.opsForValue().set("stock", (stock - 1) + "");
                    System.out.println("扣减库存成功,库存stock:" + (stock - 1));
                } else {
                    System.out.println("商品已售罄");
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return "OK";
        }
    
        /**
         * 单体式架构
         *
         * @return
         */
        @RequestMapping("/reduct")
        @ResponseBody  //直接输出字符串
        public String Reduct() {
            //System.out.println("访问接口");
            try {
                synchronized (this) {   //jvm核心技术
                    int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
                    if (stock > 0) {
                        //业务逻辑减少库存
                        stringRedisTemplate.opsForValue().set("stock", (stock - 1) + "");
                        System.out.println("扣减库存成功,库存stock:" + (stock - 1));
                    } else {
                        System.out.println("商品已售罄");
                    }
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            } finally {
            }
            return "OK";
        }
    

      

  • 相关阅读:
    Power of Cryptography
    Radar Installation
    Emag eht htiw Em Pleh
    Help Me with the Game
    89. Gray Code
    87. Scramble String
    86. Partition List
    85. Maximal Rectangle
    84. Largest Rectangle in Histogram
    82. Remove Duplicates from Sorted List II
  • 原文地址:https://www.cnblogs.com/smartsmile/p/11636736.html
Copyright © 2011-2022 走看看