当前位置: 首页> 健康> 美食 > 爱看视频的网站_会刊彩页设计_深圳最新消息今天_app推广方法及技巧

爱看视频的网站_会刊彩页设计_深圳最新消息今天_app推广方法及技巧

时间:2025/7/12 9:32:24来源:https://blog.csdn.net/m0_52062236/article/details/121888283 浏览次数:0次
爱看视频的网站_会刊彩页设计_深圳最新消息今天_app推广方法及技巧

缓存问题

核心是如何避免大量请求到达数据库

缓存穿透

既不存在于 redis,也不存在于 mysql 的key,被重复请求

public Result queryById(Long id) {String key = CACHE_SHOP_KEY+id;// 1. redis & mysqlString shopJson = stringRedisTemplate.opsForValue().get(key);if(StrUtil.isNotBlank(shopJson)){  // 非空字符串, 如"abc"Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}// 空字符串 ""if (shopJson != null){return Result.fail("not found shop");}// 2. !redis & !mysqlShop shop = shopMapper.selectById(id);if(shop == null){// 缓存 value=null 的对象stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("not fount shop");}// 3. !redis & mysqlstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);return Result.ok(shop);
}

缓存雪崩

大量key失效(可能是刚好过期,也可能是 Redis 宕机了)

  • 给不同的 key 添加 TTL 随机值
  • 使用redis集群
  • springcloud 分级缓存

缓存击穿

高并发的单key,某种原因过期了

Solution:互斥锁,逻辑过期

在这里插入图片描述

视频里用的是递归,我用了 do while,目前是没有问题的

public Result queryById(Long id) {String key = CACHE_SHOP_KEY+id;String lockKey = LOCK_SHOP_KEY+id;try {do {// 查 redisString shopJson = stringRedisTemplate.opsForValue().get(key);if(StrUtil.isNotBlank(shopJson)){  // 非空字符串, 如"abc"Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}if (shopJson != null){return Result.fail("not found shop");}boolean lock = tryLock(lockKey);if(!lock){Thread.sleep(50);} else{break;} }while (true);// 2. !redis & !mysqlShop shop = shopMapper.selectById(id);if(shop == null){// 缓存 value=null 的对象stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("not fount shop");}// 3. !redis & mysqlstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);return Result.ok(shop);}catch (InterruptedException e) {throw new RuntimeException(e);}finally {unlock(lockKey);}
}

线程安全

超卖,一人一单存在线程问题

@Transactional
public Result seckillVoucher(long voucherId) {// 查询优惠券SeckillVoucher voucher = secKillVoucherService.getById(voucherId);// 秒杀时间if(voucher.getBeginTime().isAfter(LocalDateTime.now())){return Result.fail("秒杀尚未开始");}if(voucher.getEndTime().isBefore(LocalDateTime.now())){return Result.fail("秒杀已经结束");}// 库存是否足够if(voucher.getStock()<1)return Result.fail("库存不足");// 一人一单检查Long userId = UserHolder.getUser().getId();Long count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();if(count > 0){return Result.fail("用户已经购买过了");}// 减库存, update table set stock=stock-1 where id=1 and stock>0boolean flag = secKillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherId).gt("stock", 0).update();if (flag == false) return Result.fail("库存不足");// 创建订单VoucherOrder voucherOrder = new VoucherOrder();long orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId); // order idvoucherOrder.setUser_id(userId);  // user idvoucherOrder.setVoucher_id(voucherId);save(voucherOrder);return Result.ok(orderId);
}

单机环境下的悲观锁,实现一人一单

public Result seckillVoucher(long voucherId) {//查询优惠券SeckillVoucher voucher = secKillVoucherService.getById(voucherId);// 秒杀时间if(voucher.getBeginTime().isAfter(LocalDateTime.now())){return Result.fail("秒杀尚未开始");}if(voucher.getEndTime().isBefore(LocalDateTime.now())){return Result.fail("秒杀已经结束");}// 库存是否足够if(voucher.getStock()<1)return Result.fail("库存不足");Long userId = UserHolder.getUser().getId();// 获取锁, 函数内部:提交事务(减库存,建订单), 释放锁synchronized (userId.toString().intern()){ // 按值加锁: 锁相同用户的多次请求, 而不是锁方法// 获取代理对象(事务)VoucherOrderService proxy = (VoucherOrderService) AopContext.currentProxy();return proxy.createSeckillOrder(voucherId);}}
@Transactional
public Result createSeckillOrder(long voucherId) {Long userId = UserHolder.getUser().getId();Long count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();if(count > 0){return Result.fail("用户已经购买过了");}// 减库存, update table set stock=stock-1 where id=1 and stock>0boolean flag = secKillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherId).gt("stock", 0).update();if (flag == false) return Result.fail("库存不足");// 创建订单VoucherOrder voucherOrder = new VoucherOrder();long orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId); // order idvoucherOrder.setUser_id(userId);  // user idvoucherOrder.setVoucher_id(voucherId);save(voucherOrder);return Result.ok(orderId);
}

分布式锁

通过 redis 给不同主机加锁,给锁加标识,避免被其他主机释放

问题1 锁误删情况如下:
在这里插入图片描述

改进后如下:

问题二:判断锁是自己创建的,到删除锁这段时间发生了阻塞,导致删除别人的锁,因为key都是一样的,判断是根据value


使用 redis lua 脚本,处理判断和删除的逻辑

关键字:爱看视频的网站_会刊彩页设计_深圳最新消息今天_app推广方法及技巧

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: