问题

抢购、秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:

  • 高并发对数据库产生的压力
  • 竞争状态下如何解决库存的正确减少(”超卖”问题)

常规错误写法

  • 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作
    • 不用事务,不加写锁(==高并发导致库存负数==)
    • 不用事务,只加写锁(==高并发导致库存负数==)
    • 用事务,不加锁(==高并发导致库存负数==)
    • 用事务,加读锁(==出现死锁==)
  • 先更新数据库,后查询,库存小于0,回滚
    • 用事务(==多用户并发修改同一记录,后提交的用户将覆盖前提交结果==)

优化

  1. 修改字段:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false
  2. where条件原子操作:在更新操作时加上num>0的条件
  3. 悲观锁:使用mysql的事务,查询采用排他锁
  4. 乐观锁:每次更新都会自增的version字段
  5. 文件锁:使用非阻塞的文件排他锁
  6. redis队列:因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是
    > 如上面的会导致一个用户抢多个,思路:
    需要一个排队队列和抢购结果队列及库存队列。高并发情况,先将用户进入排队队列,用一个线程循环处理从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,库存减1,写数据库,将用户入结果队列。

测试

github 地址

分类: 后端

发表评论

电子邮件地址不会被公开。 必填项已用*标注