【MySQL核心知识】使用MySQL实现秒杀的三种方法

使用MySQL实现秒杀的三种方法

概述

为什么使用MySQL秒杀是不安全的?

对于库存量限制的商品,扣减库存时一般会先查询数据库中剩余库存量,如果还有库存,则进行库存扣减操作。

在多线程场景下,假设某一时刻商品的库存量只有一个,此时正好有两个线程同时查询库存量,发现都大于零,随后他们都会执行update good set count = count - 1 where id = 1进行库存更新,这两个线程会依次执行成功,此时库存量为-1,出现了超卖问题。

如果使用MySQL解决超卖问题,一般有三种做法:悲观锁乐观锁MySQL自身锁

悲观锁

悲观锁在第一步查询的时候就将数据锁定,保证只有自己进入更新逻辑,这样避免有多个线程同时更新扣减库存。

实现原理:

  • 使用select * from good where id = 1 for update语句查询当前读,此时数据库会加锁,其他想要当前读的线程都会被阻塞。
  • 随后使用update good set count = count - 1 where id = 1 语句进行更新。

优缺点:

该方法的缺点在于将查询和更新串行化,保证某一时刻只能有一个线程更新数据库。当突然有大量请求后,由于请求串行化,所以大多数线程会因为等待而超时。

压测时,固定请求数,持续的时间会变长,但库存量最终会变为0,因为每个线程虽然等待的时间变长,但总会执行成功后才返回。

乐观锁

乐观锁通过版本号来实现,数据库设计时为每一条记录加一个版本号,通过比较版本号来判断是否有人更新过数据。

实现原理:

  • 第一步查询时,进行快照读读取当前记录的版本号(快照读不会加锁
  • 随后将版本号作为查询条件进行更新,如果版本号不一致,说明其他人已经更新过,此次更新失败,执行语句为update good set count = count - 1 where id = 1 and version = old_version

优缺点:

该方法的优点在于响应速度快,线程第一步查询时不需要阻塞等待,减少了响应时间。缺点是当同时有大量请求进来时,由于竞争激烈,绝大多数线程都不会更新成功,最终的结果就是虽然用户响应很快,但失败次数多,秒杀后还有很多库存

MySQL自身锁

还可以利用MySQL自身锁来解决问题,即每次更新前判断扣减库存后是否大于零,大于零时才会进行更新。

update good set count = count - 1 where id = 1 and count - 1 > 0

优缺点:

此方法的优点是只需要一次查询,且性能较好。缺点是由于使用了>,所以不会走索引,数据量大时性能不高。

这种方法是三种方法中性能较好的一种。

注:即使相比之下,第三种方法性能较好,但是受限于MySQL性能的问题(主要是读写磁盘的消耗),上面的方法在高并发场景下并不可靠。

更好的方法是借助Redis这种基于内存的数据库。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值