博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
避免商品超卖的4种方案
阅读量:5459 次
发布时间:2019-06-15

本文共 2096 字,大约阅读时间需要 6 分钟。

原始方案(失败):在每次下订单前我们判断促销商品的数量够不够,不够不允许下订单,更改库存量时加上一个条件,只更改商品库存大于0的商品的库存,当时我们使用ab进行压力测试,当并发超过500,访问量超过2000时,还是会出现超卖现象。

public function buyOne() {    $shop = Shop::find(1);    if ($shop->number > 0) {        DB::update("update shop set number = number - 1 where id = 1");    }}

第1种方案:使用mysql的事务加排他锁来解决,首先我们选择数据库的存储引擎为innoDB,使用的是排他锁实现的,刚开始的时候我们测试了下共享锁,发现还是会出现超卖的现象。有个问题是,当我们进行高并发测试时,对数据库的性能影响很大,导致数据库的压力很大。

//2.利用数据库的forupdate来加锁(在数量少的情况下并不会出现问题,但是当并发达到(ab -n 1000 -c 200),

//就会出现请求非2XX的响应增多,1000 失败了 60)time per request 65.195
//在高并发的情况下,会导致数据库连接数不够,部分php获取不到连接而报错,或者是超过等待时间而报错

public function indexMysql() {  DB::beginTransaction();  //通过for update 加排它锁  $shop = DB::table('shop')->where('id', '=', 1)->lockForUpdate()->first();  if ($shop->number > 0) {    if (DB::update("update shop set number = number - 1 where id = 1")) {      DB::commit();    } else {      DB::rollBack();//回滚并重试      usleep(100000);      $this->indexMysql();    }  } else {    DB::commit();  }}

第2种方案:使用文件锁实现。当用户抢到一件促销商品后先触发文件锁,防止其他用户进入,该用户抢到促销品后再解开文件锁,放其他用户进行操作。这样可以解决超卖的问题,但是会导致文件得I/O开销很大。

第3种方案:使用redis的setnx来实现锁机制。但是并发大的情况下,锁的争夺会变多,导致响应越来越慢。(与第四种方案类似)

//在数量少的情况下并不会出现问题,但是当并发达到(ab -n 1000 -c 200 就会出现请求非2XX的响应增多,1000 失败了 54) time per request 127.575

public function index() {  //测试并发超卖现象  if (Redis::setnx(self::KEY, 1)) {
//拿到了锁    $this->buy();  } else {    usleep(100000);//等会再去拿锁    //Log::info("未争夺到锁,睡眠100ms");    $this->index();  }}
private function buy() {  $shop = Shop::find(1);  if ($shop->number > 0) {    $shop->number --;    $shop->save();  }  Redis::del(self::KEY);}

第4种方案:redis的队列来实现。将要促销的商品数量以队列的方式存入redis中,每当用户抢到一件促销商品则从队列中删除一个数据,确保商品不会超卖。这个操作起来很方便,而且效率极高

//4.使用redis队列来,用户过来直接入队列,然后再将操作更新到数据库

//最佳体验(redis pconnect 9.481s, 无丢失, 无框架)

public function push() {  //入队列  Redis::lpush(self::QUEUE, 1);}

//脚本调用pop方法 * * * * * php xxx.php

public function pop() {    while (($key = Redis::rpop(self::QUEUE))) {      $shop = Shop::find(1);      if ($shop->number > 0) {        DB::update("update shop set number = number - 1 where id =         1")     }  }}

 

转载于:https://www.cnblogs.com/dawuge/p/10480469.html

你可能感兴趣的文章
idea创建Maven工程很慢的解决办法
查看>>
工作流引擎activiti入门
查看>>
cowboy rest
查看>>
setChecked方法触发onCheckedChanged监听器问题
查看>>
vim php代码规范
查看>>
numpy次方计算
查看>>
centos7 搭建LNMP
查看>>
Python OOP(1)
查看>>
delphi 数据库中Connection与Query连接数量问题思考
查看>>
JS图像变换效果的实现
查看>>
sql function递归
查看>>
【Alpha】Daily Scrum Meeting——blog2
查看>>
struts2 局部类型转换器
查看>>
all与any的用法
查看>>
SpringBoot入门教程(六)SpringBoot2.0统一处理404,500等http错误跳转页
查看>>
mysql 去除重复 Select中DISTINCT关键字的用法
查看>>
JSON
查看>>
poj1006
查看>>
win7下搭建WAMP图解(PHP运行环境:win7+Apache2.2+php5.2.8+MySQL5.5)附安装包
查看>>
二、什么是IBeamMDAA
查看>>