45、优惠券秒杀(实现一人一单)
优惠券秒杀(实现一人一单)
案例:(一人一单)
旧的:
这种优惠券优惠力度大应该一人只能消费一次。问题(我们一个人全抢了)
优化:(我们在库存充足的时候不是直接扣减库存的,而是判断一下这个订单是否存在了。不存在才扣减库存)
一人一单操作:
第一步:查询订单嘛(才能判断(将下面的查询用户id提上来先用))
第二步:判断是否存在了(不存在返回失败)
第三步:不存在还是之前的扣减库存
测试:(200并发应该只能卖一单)
出现了错误(这个1个用户还是下了多单)
问题分析:我们这里的逻辑与前面的库存思想是一样的,先查询再判断再扣减
按时我们的这里是多线程操作(也是出现了多线程穿插的情况)即为当我们第一个线程在判断出这个用户不存在0,但是还未扣减库存(用户信息添加进数据库(没有订单))的时候,其他线程也进来获取了也是0,他的判断还是没有。所以逻辑还是会让它扣减的。
解决(优化)思路:(还是加锁啊,这里就不能更新再来判断了,就必须是悲观锁了(syn))
第一步:我们这个整个逻辑(一人一单)进行封装:Ctrl+m。(就是将下面的变为一个函数,上面使用的时候直接调动)
封装好了(调用下面的封装函数)
第二步:加锁(我们是先加在方法上的(syn),但是这样就锁住了整个方法,每个用户来都要获取锁,串行效率很慢)而且我们的事务范围是这个扣减库存的操作而不是整个类上面(前面是查询不需要加事务嘛)所以我们就将事务放到下面的这个锁的方法上了。
第三步:(优化:不要将整个方法锁住(提高效率),锁用户)
思路:我们缩小锁的范围,(我们只锁我们的用户id从而锁住我们的用户)一人一单中,我们只有在同一个用户来的时候我们才进行判断了(他的并发安全问题),其他用户我们就不加锁了。我们就使用关键字这种方法了(syn)锁住这个id再将下面的加在代码块中。
这里有个坑:
坑1:(我们这里是将id值一样的作为一把锁)但是我们每一次请求来这个id对象其实都是不同的,我们的对象变了,那么我们的锁也就变了(我们锁的操作是对象的,这是基本别忘了)。我们这里的tostring是不能保证其是根据值来加锁的。请看源码,其底层调用的是这个Long的一个静态函数,内部是一个new String()。New了一个字符串。所以我们再每一次调用这个toString的时候也是一个全新的字符串对象。所以这个锁对象又变了一次。(即使id是一样的(字符串),但是字符串对象还是不一样的)
优化1、(调用一个字符串方法,它的值相同返回的对象是一样的toString().intern())
确保当我们的用户的id一样的时候,锁是一样的。(锁的是当前用户)
坑2:(我们这里的锁范围又有点小了)我们的这个事务提交问题(我们是在方法内部加锁),我们这个事务是被spring管理的(@Transactiona)所以这个事务的提交是在我们函数执行完以后由spring才做的提交。
逻辑:我们先去开启事务,开始执行,然后获取锁,我们开始做下面的查询,查询我们再减库存,提交订单。这时我们是先释放锁再才会提交事务。那么在这个函数的最后的}结束后,这个锁就已经释放了(锁释放到spring提交事务中间还有点时间)。那么其他的线程就能够进来了。此时事其他线程进来查询订单(此时事务还没有提交,我们下面新增的订单还没有写入我们的数据库(和前面的数据库事务串起来。我们修改的时候只是改的表的数据,只有提交后数据库才会永久更改了))那么他也会进行扣减库存操作了(还是出现并发安全问题)
优化2、我们应该是在事务提交后才释放锁(我们将syn加在这个函数调用前面去加锁了)
坑3、上面优化后又出现事务问题了(我们是对下面的那个函数加了事务,没有给外面的这个函数(方法)加事务而外面这个函数再调用的时候是this.这样调用的 。其中他this拿到的是(目标对象不是代理对象)这个对象,而不是我们需要的他的代理对象。而我们需要知道我们的事务想要生效是我们的spring对这个类做了动态代理,拿到了这个类的代理对象。然后用这个下面函数做了事务处理)this拿到的是目标对象,而不是代理对象(代理对象才能做很多目标对象无法做的东西操作)没有事务操作功能的(这就是spring事务失效的几种可能性之一)。
优化3:我们去拿到我们事务的代理对象(AopContext.currentProxy()拿到代理对象也就是service接口嘛(别忘了我们代理这些都是实现了同一个接口))
最后我们还需要加一个依赖org.aspectj
再到这个启动类上去去加注解暴露这个代理对象true(暴露)
测试:
莫得问题了
45、优惠券秒杀(实现一人一单)相关推荐
- Redis解决秒杀中一人一单问题
前言 在上一篇,通过实例演示了在高并发场景下多人抢购优惠券的超卖问题,并且利用redis+lua解决了超卖问题,但是一人只能抢一单的问题是否还在呢? 一人抢多单压测 可以发现,在经过改造时候,虽然解决 ...
- Redis 基础 - 优惠券秒杀《非集群》
参考 Redis基础 - 基本类型及常用命令 Redis基础 - Java客户端 Redis 基础 - 短信验证码登录 Redis 基础 - 用Redis查询商户信息 摘要 用Redis生成保证唯一性 ...
- 【Redis】实战篇:优惠卷秒杀 (库存超卖问题、一人一单问题)
文章目录 3.1 全局唯一ID 3.2 -Redis实现全局唯一Id 3.3 添加优惠卷 3.4 实现秒杀下单 3.5 库存超卖问题分析 3.6 乐观锁解决超卖问题 3.7 优惠券秒杀-一人一单 3. ...
- Redis实战11-实现优惠券秒杀下单
本篇,咱们来实现优惠券秒杀下单功能.通过本篇学习,我们将会有如下收获: 1:优惠券领券业务逻辑: 2:分析在高并发情况下,出现超卖问题产生的原因: 3:解决超卖问题两种方案:版本号法及CAS法 4:乐 ...
- 实战篇--优惠券秒杀
优惠券秒杀 全局唯一ID 当用户抢购时,就会生成订单并保存到tb_voucher_order这张表中,而订单表如果使用数据库自增ID就存在一些问题: id的规律性太明显 受单表数据量限制 全局ID生成 ...
- Redis(4)优惠券秒杀
优惠券秒杀 全局ID生成器 优惠券秒杀 秒杀实现 库存超卖 乐观锁实现 一人一单 分布式锁 分布式锁版本一 Redis分布式锁误删情况 解决分布式锁误删 分布式锁原子性问题 解决原子性问题 利用Jav ...
- 【Redis学习05】优惠券秒杀及其优化
文章目录 1. 全局唯一ID 1.1 全局唯一ID介绍及生成策略 1.2 代码实现 1.3 总结 2. 优惠券秒杀下单 2.1 添加优惠券 2.2 优惠券秒杀功能 3. 超卖问题 3.1 问题分析 3 ...
- Redis(八) - Redis企业实战之优惠券秒杀
文章目录 一.全局唯一ID 1. 全局ID生成器 2. 全局唯一ID生成策略 3. Redis自增ID策略 二.实现优惠券秒杀下单 1. 添加优惠券 2. 编写添加秒杀券的接口 三.实现秒杀下单 四. ...
- Redis 基础 - 优惠券秒杀《初步优化(异步秒杀)》
Redis基础 - 基本类型及常用命令 Redis基础 - Java客户端 Redis 基础 - 短信验证码登录 Redis 基础 - 用Redis查询商户信息 Redis 基础 - 优惠券秒杀< ...
最新文章
- 热烈庆祝 ubuntu10.10发布
- ubuntu安装mysql远程_Ubuntu18.04下远程安装MySQL
- 文本”Hello, world.”显示的颜色是?
- vue 前期准备,项目结构
- volatile深入
- 计算机网络数据链路层次学习
- 【英语学习】【English L06】U07 Jobs L4 What do you think of our service?
- Look at Memory Cost via Batch Size
- 1200万!硅谷AI大牛一年赚够北京二环一套房
- Android ListView 滑动背景为黑色的解决办法 listview小知识整理
- tensorflow2.1学习--熟悉TensorFlow写整个项目即鸢尾花项目
- Linux虚拟机设置Samba服务
- 苹果电脑python编程里面怎么切到中文_苹果电脑输入法怎么切换到中文
- GoldenDict 上的那些精美版权词典(附下载地址)(英语、俄语、梵语、印地语)
- Spring Boot之自定义JSON转换器
- 扩展点系列之ApplicationContextAwareProcessor普通类获取Spring Bean - 第433篇
- 中小企业网站十大通病,你的站有没有?
- HTML元素分类:inline、inline-block、block
- 3U8633——雷达对民航的贡献
- 操作系统春招面试复习之:文件管理
热门文章
- 【NOIP普及组】 1945:【09NOIP普及组】多项式输出
- JUC-II CPU的微程序设计 计算机组成原理课程设计 微指令编码
- 非华为电脑多屏协同_苹果转华为后的真香体验1-非华为电脑体验跨屏协同,好用...
- 招聘运维开发leader
- 服务器:连接云服务器的端口是什么?
- 2.7 数值分析: 向量的范数
- 分布式学习(6)etcd@3@ API v3 gRPC_range,put,deleterange
- 全球十大外盘外汇交易平台排行榜
- Python练手项目:用中国地图验证四色地理
- 加密解密,MySQL单行函数,数学函数字符串日期时间,流程控制,完整详细可收藏查询SQL