如何解决高并发秒杀的超卖问题

如何解决高并发秒杀的超卖问题
 
由秒杀引起的一个问题
  • 秒杀最大的一个问题就是解决超卖的问题。其中一种解决超卖以下方式:
1 update goods set num = num - 1 WHERE id = 1001 and num > 0
 
咱们假设如今商品只剩下一件了,此时数据库中  num = 1;
 
但有100个线程同时读取到了这个  num = 1,因此100个线程都开始减库存了。
 
但你会最终会发觉, 其实只有一个线程减库存成功,其余99个线程所有失败。
 
为什么?
 
这就是MySQL中的排他锁起了做用。
 
排他锁又称为写锁,简称X锁,顾名思义,排他锁就是不能与其余所并存, 如一个事务获取了一个数据行的排他锁,其余事务就不能再获取该行的其余锁,包括共享锁和排他锁,可是获取排他锁的事务是能够对数据就行读取和修改。
就是相似于我在执行update操做的时候,这一行是一个事务 (默认加了排他锁)。 这一行不能被任何其余线程修改和读写
 
 
  • 第二种解决超卖的方式以下
 
1 select version from goods WHERE id= 1001
2 update goods set num = num - 1, version = version + 1 WHERE id= 1001 AND num > 0 AND version = @version(上面查到的version);

 

 
这种方式采用了 版本号的方式,其实也就是 CAS的原理。
 
假设此时version = 100, num = 1; 100个线程进入到了这里,同时他们select出来版本号都是version = 100。
 
而后直接update的时候,只有其中一个先update了,同时更新了版本号。
 
那么其余99个在更新的时候,会发觉version并不等于上次select的version,就说明version被其余线程修改过了。那么我就放弃此次update
 
  • 第三种解决超卖的方式以下
 利用redis的单线程预减库存。好比商品有100件。那么我在redis存储一个k,v。例如 <gs1001, 100>
 
每个用户线程进来,key值就减1,等减到0的时候,所有拒绝剩下的请求。
 
那么也就是只有100个线程会进入到后续操做。因此必定不会出现超卖的现象
 
  • 总结
 
可见第二种CAS是失败重试,并没有加锁。应该比第一种加锁效率要高不少。 相似于Java中的Synchronize和CAS
相关文章
相关标签/搜索