- 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";
- }
来源: http://www.bubuko.com/infodetail-3230885.html