2.1K Star 13.9K Fork 5.8K

GVP小柒2012 / spring-boot-seckill

 / 详情

redis分布式秒杀1 更新和保存执行顺序导致超卖

待办的
创建于  
2021-04-15 17:10

秒杀都是先保存后更新,保存成功,但是更新不一定会成功
dynamicQuery.save(killed);
nativeSql = "UPDATE seckill SET number=number-1 WHERE seckill_id=? AND number>0";
dynamicQuery.nativeExecuteUpdate(nativeSql, new Object[]{seckillId});

如果更新语句执行完成就不会超卖了 redis分布式锁情况下
nativeSql = "UPDATE seckill SET number=number-1 WHERE seckill_id=? AND number>0";
int i = dynamicQuery.nativeExecuteUpdate(nativeSql, new Object[]{seckillId});
if (i > 0) {
SuccessKilled killed = new SuccessKilled();
killed.setSeckillId(seckillId);
killed.setUserId(userId);
killed.setState((short)0);
killed.setCreateTime(new Timestamp(new Date().getTime()));
dynamicQuery.save(killed);
}

评论 (1)

The History 创建了任务
展开全部操作日志

调整更新和保存调用的顺序和判断应该就是保证了:一笔秒杀处理的原子性。
此时把redis分布式锁拿掉也是可以的。
针对RR级别隔离,不管是分布式锁,内存锁,都务必将锁提到事务开启前。
事务开启后才加锁,存在这样的情景:
在两个事务里分别获取到锁时,读取的是同一份数据,
然后两个线程在线程已安全的错觉下不再额外判断数据仅做业务处理时,
对相同的数据进行同样的业务处理,就会出现数据覆盖的问题,就是这里的超卖问题。
既然加了锁就不要加一个没实际作用的锁,加锁也是有成本的,特别是高并发下,加锁成本还是蛮高的

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(2)
1860974 clmmxdc 1607952369
Java
1
https://gitee.com/52itstyle/spring-boot-seckill.git
git@gitee.com:52itstyle/spring-boot-seckill.git
52itstyle
spring-boot-seckill
spring-boot-seckill

搜索帮助