自学内容网 自学内容网

redis学习(014 实战:黑马点评:优惠券秒杀——1人只可以下1单问题解决方案)

黑马程序员Redis入门到实战教程,深度透析redis底层原理+redis分布式锁+企业解决方案+黑马点评实战项目

总时长 42:48:00 共175P

此文章包含第54p-第p55的内容


一人一单问题分析

在这里插入图片描述

不能让一个人把所有的优惠券都拍下来了

在这里插入图片描述

第一种写法 查询后进行添加

在这里插入图片描述
这里我们发送200个请求 这些请求是同一个用户的token,我们设置初始库存为100

在这里插入图片描述
测试请求200个 预期失败99.5%,这里我们发现失败率是95%,库存变成了90,没有锁住,因为存在线程并发问题,例:线程1查询后发现这个用户没抢过优惠券,准备添加订单,这时候线程2查询后发现这个用户没抢过优惠券,准备添加订单,这样就出现并发问题了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第二种写法 加悲观锁

乐观锁在更新数据时使用,这是插入数据 只能加悲观锁

  1. 先将(查询订单、扣减库存、生成订单)这段逻辑抽离成一个新的方法
    在这里插入图片描述
  2. 快捷键 ctrl+alt+m 抽离代码生成新的方法
    在这里插入图片描述
  3. 修改方法名
    在这里插入图片描述
  4. 在当前加锁,并修改成public然后加事务注解@Transactional 在这里插入图片描述
    这样加锁 就相当于整个方法都加锁了 谁来查都要等待,我们只需要判断同一用户是否添加过即可,所以我们在用户id上加锁即可

在用户上加悲观锁(提升性能)

  1. 在用户上加锁
    在这里插入图片描述
  2. toString()方法无法保证userId相同
    在这里插入图片描述
    这里是new了一个对象,所以每次传进来的用户ID都是新的对象
    在这里插入图片描述
    我们使用intern方法(常量池里查找,但是这样数据量太大的话,会产生常量池溢出)
    在这里插入图片描述
    这里还有问题 因为先释放锁才能提交事务,这里的事务是在方法提交完之后再由spring进行提交
    在这里插入图片描述
    主要原因:当前事务的隔离级别是:可重复读

这样加锁可以,事务提交完再释放锁
在这里插入图片描述

事务失效

这里的方法是this(我们自动省略了this.) ,this.createVoucherOrder指的是目标对象的的方法 所以会造成事务失效。

在这里插入图片描述

事务失效的底层原因

因为如果在同一个Service中,方法A(未加@Transactional)调用方法B(加了@Transactional),那么事务可能会失效。这是因为Spring的事务管理是基于代理的,当方法A直接调用方法B时,不会触发B的方法代理,因此B的事务不会生效。

要确保B方法的事务有效,可以将方法B调用提取到另一个Service中,或者在A方法上也添加@Transactional。

事务失效的原因主要在于Spring的AOP代理机制。当你在一个类的方法上添加@Transactional时,Spring会为该类创建一个代理对象,以管理事务。以下是具体原因:

代理机制: Spring使用动态代理(JDK或CGLIB)来处理@Transactional。当你调用一个带有事务注解的方法时,代理会在方法执行前启动事务,在方法执行后提交或回滚事务。

直接调用: 如果在同一个类中,方法A直接调用方法B,实际上是通过this引用调用,因此不会触发代理,B方法的事务管理就不会生效。

解决方案: 为了解决这个问题,可以将方法B移到另一个Service中,这样调用时就会通过代理,从而确保事务生效。

Spring的设计: 这种设计是为了优化性能和减少复杂性,但也导致了开发者在使用时需要注意方法调用的上下文。

解决代码

如果直接使用目标对象,Spring将无法在方法调用前后执行必要的事务管理操作,因为它依赖于代理机制来插入这些事务管理步骤。

事务底层是aop实现的 因此 调用被包装方法应该采用aopcontext

我们使用代理对象进行调用,就可以防止事务失效了

在这里插入图片描述
记得引入aspectj依赖
在这里插入图片描述

暴露代理对象
在这里插入图片描述
在这里插入图片描述

修改完成后 我们重启项目 ,然后进行测试

这里再开启200条请求进行测试,预计失败率99.5%,只能成功一条
在这里插入图片描述

这里测试完成后确实是99.5%,只成功了一条
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

模拟集群

这种情况只适合单机情况下使用,分布式集群下还是使用分布式锁比较好
在这里插入图片描述

使用多个tomcat

ctrl+D 把当前的启动项copy了一份,复制一个新的tomcat
在这里插入图片描述
添加配置项 修改端口号
在这里插入图片描述
新版IDEA配置,点击Modify options->Add VM options

修改nginx配置文件-负载均衡到两个端口

在这里插入图片描述
这里的nginx使用8080端口,负载均衡到8081和8082
在这里插入图片描述

负载均衡
在这里插入图片描述
打开注解,实现负载均衡
这里的42行被注释了,第43,48,49行都要放开,不要漏了
在这里插入图片描述

重新加载nginx配置文件
在这里插入图片描述

调用两次请求
在这里插入图片描述
这里都可以看见日志,证明负载均衡配置完成
在这里插入图片描述

我们调用两次锁 结果发现没有锁住 两个tomcat都执行了一次,扣了两个库存
在这里插入图片描述

原因

正常情况

在这里插入图片描述
这样会出现多次添加

在这里插入图片描述
解决方案 加锁
在这里插入图片描述
所以单机可以锁住

两个JVM

每个tomcat都有自己的虚拟机
在这里插入图片描述

分布式不一定是集群,但集群一定是分布式。

这里就需要分布式锁了,下一篇笔记进行讲解



原文地址:https://blog.csdn.net/wang_book/article/details/142362622

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!