其实真是的秒杀不是这样的
作为java的多年经验的码农觉得老师的东西很怪异,CAS原理都不讲的,你用mysql的锁去应对秒杀基本就死在哪里了。
1、老师说得这个行锁很怪异,mysql根本就没有这个东西,没有加for update你会有行锁吗?不知道老师所谓的行锁是从天而降吗??这个称为悲观锁。但是代价太大,我们基本不用。因为使用它,你所有的线程就等着挂起和等待了,系统就基本就死在哪里了。
2、一般我们即时使用数据库,也不会这样用,应该加一个version字段。
(1)首先是程序读取select version, left from table;
(2)然后记录version字段(旧值),判定left - buyCount(购买数量)>=0,如果否退出,结束业务。否则继续(3)
(3)开始执行减库存
update table set left = left - #{byCount} , version = version+1
where count >0 and vesion = #{vesion}//这个version是旧值,而更新一次成功version就加1
这里数据库并没有任何锁,但是这里巧妙的使用了version字段,符合一个CAS原理,就是我当初读出的version(旧值)和实时数据库的version(当前需要更新时刻的实时值)是否一致,如果一致,则我会认为这条记录没有被其他线程修改,则减库存成功,如果不一致则我会认为其他线程修改过这个记录。就不会进行操作这个被称为乐观锁。这个时候我们会考虑重入,重复执行(1)-(3)步骤直至(2)的退出或者(3)成功继续我们的操作,这样就是一个没有锁的机制。这就是一个乐观锁的机制,而没有任何等待的机制,是一个非阻塞的过程。
3、企业的秒杀目前应该考虑使用redis,而不是mysql。
别和我说你mysql的性能和redis比,个人自测分别批量插入数据:
redis每秒在我的机子可以执行40万次的插入,而mysql只能执行不到2万次。这个性能差了几十倍。你用mysql是自己找麻烦。这个级别根本不同级,其次redis提供的事务很好的符合了秒杀的功能。
首先任何线程执行redis的操作的时候都是使用lua语言,redis在执行lua语言的时候是原子性的,让它执行减库存,并且记录用户购买记录。
直至秒杀时间到期或者库存为0,才考虑将redis缓存的数据批量一次性把减库存和用户购买的信息批量写入mysql。整个秒杀过程基本在redis完成,而不是数据库,不是你mysql的性能可比的,你服务器上mysql一秒可以4万次,redis可以上百万次,你怎么比??