当然了你也可以用Spring自带的事务注解来实现悲观锁
的操作,因为用了@Transactional
就可以实现通过事务来控制,要么全部成功,要么全部失败,用事务时有两点需注意:
尽可能将MySQL执行语句往方法体后面靠,因为MySQL事务的commit语句是在第一次执行MySQL相关语句开始,一直到方法的结束。
设置事务的超时时间,如果不设置默认是-1是无限长。并且事务中设置的耗时timeout = 最后一个MySQL语句耗时 + 以及最后一个MySQL之前的所有耗时。
需注意:悲观锁状态下会保证商品卖出去,如果没拿到锁的线程会阻塞的等待拿锁。但是他的阻塞也会给用户带来非常不良好的体验。
4 第3版-乐观锁
我们为每个数量的已售数据配备个版本号,在
Service
层调用时获得用户的已售数跟对应版本号,然后更新时将已售数跟版本号同时更新。因为 MySQL在更新时会自带乐观加速机制,如果更新成功则表示抢购成功,更新失败则表示抢购失败,此时你会发现不是手速越快就一定能抢到的哦,但起码保证了不会超卖, 6 第5版- 细节优化
有了乐观锁跟限流,接下来再思考写细节问题。
秒杀要有时间范围限制的,不能再任意时刻都可以接受秒杀请求,要实行
限时抢购
。如果有懂IT人员通过抓包获取了秒杀接口地址,在秒杀开始时,不通过按钮,直接通过脚本秒杀咋办?要实行
秒杀接口隐藏
。每个用户单位时间内访问次数要做
频率限制
。
6.1 限时抢购
很简单,将秒杀商品放入Redis并设置超时,比如我们以kill + 商品id作为key,以商品id作为value,设置180秒超时。
加入时间校验:
6.2 秒杀接口隐藏
用户秒杀前先通过getMd5方法获得一个请求秒杀URL的MD5值。
请求getMd5算法,Key = 商品id + 用户id,value = 商品id + 用户id + 盐 。将KV存入redis并且设置过期时间,最终返回value作为md5值。
用户请求秒杀URL的时候需携带MD5值,然后Service层会根据商品id + 用户id从redis中获取下对应的value,看这个value跟MD5值是否一致,绝对下一步操作。
此时如果用户直接请求秒杀接口就会被限制了,但如果黑客技术升级,将请求MD5跟请求秒杀接口写到一起,还是无法防止被薅羊毛!咋办呢?再限制下用户访问频率。
6.3 访问频率限制
通过前面请求后根据用户id生成个redis中的key,value为访问次数,默认为0,并且设置好该KV的过期时间。
用户在验证是否通过秒杀隐藏接口验证前,先看下他的单位时间内访问次数是多少,如果超过阈值则直接拒绝,没超过再进行隐藏接口的验证。
这里只是举例为用户访问次数限制,IP访问次数限制类似。
秒杀源码公众号回复
秒杀
获取。
本文分享自微信公众号 - sowhat1412(sowhat9094)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。