黑马程序员Redis入门到实战教程,深度透析redis底层原理+redis分布式锁+企业解决方案+黑马点评实战项目
总时长 42:48:00 共175P
此文章包含第54p-第p55的内容
文章目录
- 一人一单问题分析
- 第一种写法 查询后进行添加
- 第二种写法 加悲观锁
- 在用户上加悲观锁(提升性能)
- 事务失效
- 事务失效的底层原因
- 解决代码
- 模拟集群
- 使用多个tomcat
- 修改nginx配置文件-负载均衡到两个端口
- 原因
- 正常情况
- 两个JVM
一人一单问题分析
不能让一个人把所有的优惠券都拍下来了
第一种写法 查询后进行添加
这里我们发送200个请求 这些请求是同一个用户的token,我们设置初始库存为100
测试请求200个 预期失败99.5%,这里我们发现失败率是95%,库存变成了90,没有锁住,因为存在线程并发问题,例:线程1查询后发现这个用户没抢过优惠券,准备添加订单,这时候线程2查询后发现这个用户没抢过优惠券,准备添加订单,这样就出现并发问题了
第二种写法 加悲观锁
乐观锁在更新数据时使用,这是插入数据 只能加悲观锁
- 先将(查询订单、扣减库存、生成订单)这段逻辑抽离成一个新的方法
- 快捷键 ctrl+alt+m 抽离代码生成新的方法
- 修改方法名
- 在当前加锁,并修改成public然后加事务注解@Transactional
这样加锁 就相当于整个方法都加锁了 谁来查都要等待,我们只需要判断同一用户是否添加过即可,所以我们在用户id上加锁即可
在用户上加悲观锁(提升性能)
- 在用户上加锁
- 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都有自己的虚拟机
分布式不一定是集群,但集群一定是分布式。
这里就需要分布式锁了,下一篇笔记进行讲解