记一次秒杀重复抢单问题

背景描述:

系统给APP用户(客户经理)定时推送一批客户资源数据,这批数据在不同的客户经理登录APP都能看见,然后点击抢的按钮,就可以获取这个客户了,这种场景类似于秒杀抢单,存在多人同时点击按钮抢人,所以伴随着较高的并发操作。

问题描述:

这时候问题就出来了,同一个地区的客户经理都可以看到相同的客户,所以他们在抢通一个客户的时候,就会出现同时抢中的情况。

背景设置:

线上环境mysql隔离级别配置是 提交读,zk分布式锁超时时间为10s,myql没有设置唯一索引。

问题分析:

抢单更新库存方法采用的是zk分布式锁,按理说不应该出现,两个经理同时抢中的情况。分析代码执行流程:

在这里插入图片描述

那么可能存在的一种情况:A先获取锁逻辑执行完了会释放锁,但事务未提交,同时超时时间未到;因为超时时间未到B仍在等待获取锁,等A一释放B可以马上获取锁,因为A事务未提交,B仍然可以通过校验,这样最终撞车了,导致AB同时抢到了客户。因为没有唯一索引,所以AB都可以更新数据。

还存在另一种可能:由于对zk分布式锁进行了一层封装,所以zk工具类存在两个超时时间,第一个是默认的zk锁超时时间,第二个超时就是个保险,如果真的执行了半天还不释放,就强制释放掉,也不能一直站着坑。
这就可能存在问题,A先获得锁,等待第一个超时时间过了,B线程会抛异常,B线程会回滚。然后又等到了第二个超时时间过了,不管A执行是否完毕,A都会释放锁。这时候恰好C线程趁虚而入获取了锁,这样会导致A和C同时抢中了客户,这时候如果强制释放锁的时候,没有中断、回滚A线程执行逻辑,就会出现重复抢单问题。

解决方案:

1. 把查询的方法和抢单的方法都分别提取去来,作为两个子方法,分别加了一个事务,通过事务保证唯一性。

2. zk锁的超时时间设置为0,即A先获取锁,则B不在等待,直接抛异常返回提示。

3. mysql最好添加唯一索引,作为一层保障,让脏数据写不进去。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值