日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

php 和mysql实现抢购功能_php处理抢购类功能的高并发请求

發布時間:2024/10/8 数据库 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php 和mysql实现抢购功能_php处理抢购类功能的高并发请求 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文以搶購、秒殺為例。介紹如何在高并發狀況下確保數據正確。

在高并發請求下容易參數兩個問題

1.數據出錯,導致產品超賣。

2.頻繁操作數據庫,導致性能下降。

測試環境

Windows7

apache2.4.9

php5.5.12

php框架 yii2.0

工具 apache bench (apache自帶高并發請求工具)。

通常處理方法

從控制器可以看出代碼思路。先查詢商品庫存。如果庫存大于0 ,則庫存減少1,同時生產訂單,錄入搶購者數據。

// 常規代碼處理高并發

public function actionNormal(){

// 查詢庫存

$stock = Goods::find()->select('stock')->where(['goods_id'=>100001])->asArray()->one();

// 判斷該商品是否還有庫存

if ($stock['stock']>0) {

// 庫存減一

Goods::updateAllCounters(['stock' => -1],['goods_id'=>100001]);

// 生產訂單(另外功能,暫且隨機賦值)

$order = $this->build_order();

// 秒殺信息入庫

$model = new Highly();

$model->order_id = $order;

$model->goods_name = '秒殺商品';

$model->buy_time = date('Y-m-d H:i:s',time());

$model->mircrotime = microtime(true);

if($model->save()===false){

echo '未能成功搶購!';

}else{

echo '恭喜你,訂單'.$order.'搶購成功';

}

}else{

echo '已被搶購一空!';

}

}

將商品庫存設置為20后,通過ab 配置200的并發請求。

ab -n 200 -c 200 http//localhost/highly/normal

執行結果發現庫存變成了負值,商品超賣了。

原因比較簡單,在高并發請求下。在生產訂單,減少庫存之前,會優先查詢到庫存結果。

優化一:修改庫存數據類型

第一種優化方法,從數據庫入手。既然查詢到的結果不準確,那我就在庫存減少上做手腳。將庫存的數據類型改成無符號(不能有負值)。

代碼還是跟上面差不多,只是在庫存減1的地方做了個判斷。避免報錯。

public function actionNormal(){

// 查詢庫存

$stock = Goods::find()->select('stock')->where(['goods_id'=>100001])->asArray()->one();

// 判斷該商品是否還有庫存

if ($stock['stock']>0) {

// 庫存減一

if(Goods::updateAllCounters(['stock' => -1],['goods_id'=>100001])===false){

echo "已被搶購一空!";

return false;

}

// 生產訂單(另外功能,暫且隨機賦值)

$order = $this->build_order();

// 秒殺信息入庫

$model = new Highly();

$model->order_id = $order;

$model->goods_name = '秒殺商品';

$model->buy_time = date('Y-m-d H:i:s',time());

$model->mircrotime = microtime(true);

if($model->save()===false){

echo '未能成功搶購!';

}else{

echo '恭喜你,訂單'.$order.'搶購成功';

}

}else{

echo '已被搶購一空!';

}

}

這一次同樣200的并發,執行結果發現。數據正確,并不會出現超賣的情況。

思路其實也比較簡單。因為庫存不能為負值,當庫存等于0時,如果還有值傳進來,則會報錯。請求被終止。

這種優化方式,雖然避免了商品超賣的情況。但是在另一方面,請求仍然會對數據庫造成壓力。如果多個功能使用此數據庫,會造成性能下降厲害。

優化二:redis

利用 redis list類型的pop的原子性。在操作數據庫前,做一個驗證。當商品賣完后,就不允許再繼續進行數據庫操作。

// redis list 高并發測試

public function actionRedis(){

$redis = \Yii::$app->redis;

// $redis->lpush('mytest',1);

$order = $this->build_order();

// echo $order;die;

// echo $redis->llen('mytest');

$reg = $redis->lpop('mytest');

if (!$reg) {

echo "笨蛋!已經被搶光啦!";

return false;

}

$redis->close();

$model = new Highly();

$model->order_id = $order;

$model->goods_name = '秒殺商品';

$model->buy_time = date('Y-m-d H:i:s',time());

$model->mircrotime = microtime(true);

if($model->save()===false){

echo '未能成功搶購!';

}else{

echo '恭喜你,訂單'.$order.'搶購成功';

}

}

// 給redis添加商品

public function actionInsertgoods(){

$count = yii::$app->request->get('count',0);

if (empty($count)) {

echo '大兄弟,你還沒告訴我需要上架多少商品呢!';

return false;

}

$redis = \Yii::$app->redis;

for ($i=0; $i < $count; $i++) {

$redis->lpush('mytest',1);

}

echo '成功添加了'.$redis->llen('mytest').'件商品。';

$redis->close();

}

這點的代碼,我寫了兩個方法。第一個方法是秒殺的代碼,第二個方法是給秒殺的商品設置數量。為了方便測試,我這里處理的比較簡單。

通過測試,數據庫生產的訂單數量正常,并沒有出現問題。而又避免了請求數據庫造成性能下降的問題。同時內存數據庫redis查詢的速度要比mysql快很多。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持聚米學院。

總結

以上是生活随笔為你收集整理的php 和mysql实现抢购功能_php处理抢购类功能的高并发请求的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。