最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

thinkphp6使用mysql悲觀鎖解決商品超賣問題的實現(xiàn)

 更新時間:2021年11月23日 09:25:37   作者:每天至少八杯水1688  
這篇文章主要介紹了thinkphp6使用mysql悲觀鎖解決商品超賣問題的實現(xiàn)

悲觀鎖介紹(百科):

悲觀鎖,正如其名,它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當前的其他事務,以及來自外部系統(tǒng)的事務處理)修改持保守態(tài)度,因此,在整個數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機制(也只有數(shù)據(jù)庫層提供的鎖機制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實現(xiàn)了加鎖機制,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))。

使用場景舉例:以MySQL InnoDB為例

商品goods表,假設商品的id為1,購買數(shù)量為1,status為1表示上架中,2表示下架?,F(xiàn)在用戶購買此商品,在不是高并發(fā)的情況下處理邏輯是:

  • 查找此商品的信息;
  • 檢查商品庫存是否大于購買數(shù)量;
  • 修改商品庫存和銷量;

上面這種場景在高并發(fā)訪問的情況下很可能會出現(xiàn)問題。如果商品庫存是100個,高并發(fā)的情況下可能會有1000個同時訪問,在到達第2步的時候,都會檢測通過。這樣會出現(xiàn)商品庫存是-900個的情況。顯然著不滿足需求?。?!

商品表結(jié)構(gòu):

CREATE TABLE `goods` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  `status` tinyint(1) NOT NULL DEFAULT '1',
  `total` int(11) NOT NULL DEFAULT '0',
  `sell` int(11) NOT NULL DEFAULT '100',
  `price` decimal(10,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
 
INSERT INTO `test`.`goods`(`id`, `name`, `status`, `total`, `sell`, `price`) VALUES (1, '商品', 1, 0, 100, 15.00);

訂單表結(jié)構(gòu):

CREATE TABLE `orders` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL DEFAULT '0',
  `create_time` datetime NOT NULL,
  `status` tinyint(1) NOT NULL DEFAULT '1',
  `goods_id` int(11) NOT NULL DEFAULT '0',
  `order_no` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

使用悲觀鎖處理。

當我們在查詢出goods信息后就把當前的數(shù)據(jù)鎖定,直到我們修改完畢后再解鎖。那么在這個過程中,因為goods被鎖定了,就不會出現(xiàn)有第三者來對其進行修改了。

注:要使用悲觀鎖,我們必須關閉mysql數(shù)據(jù)庫的自動提交屬性,因為MySQL默認使用autocommit模式,也就是說,當你執(zhí)行一個更新操作后,MySQL會立刻將結(jié)果進行提交。thinkphp6中使用事務,手動進行提交回滾。

<?php
 
namespace app\controller;
 
use app\BaseController;
use think\facade\Db;
 
class Test extends BaseController
{
 
    /**
     * 不加鎖
     * @return string|void
     */
    public function test_1()
    {
        $num = 1;
        $goods_id = 1;
        Db::startTrans();
        try {
            $where = [];
            $where['id'] = $goods_id;
            $where['status'] = 1;
            $goods_info = Db::table('goods')->where($where)->find();
            if (empty($goods_info)) {
                return '商品不存在';
            }
            $total = $goods_info['total'];
            $sell = $goods_info['sell'];
            if ($total < $num) {
                return '庫存不足';
            }
            $data['total'] = $total-$num;
            $data['sell'] = $sell+$num;
            $res = Db::table('goods')->where(['id'=>$goods_id])->update($data);
            $order_data = [];
            $order_data['uid'] = rand(1000,9999);
            $order_data['status'] = 1;
            $order_data['create_time'] = date('Y-m-d H:i:s');
            $order_data['goods_id'] = $goods_id;
            $order_data['order_no'] = date('YmdHis').rand(1000,10000);
            $order_res = Db::table('orders')->insert($order_data);
            Db::commit();
        } catch (\Exception $e) {
            // 回滾事務
            Db::rollback();
            echo $e->getMessage();
            exit('rollback');
        }
        echo '請求成功';
    }
 
    /**
     * 加鎖--悲觀鎖
     * @return string|void
     */
    public function test_2()
    {
        $num = 1;
        $goods_id = 1;
        Db::startTrans();
        try {
            $where = [];
            $where['id'] = $goods_id;
            $where['status'] = 1;
            $goods_info = Db::table('goods')->lock(true)->where($where)->find();
            if (empty($goods_info)) {
                return '商品不存在';
            }
            $total = $goods_info['total'];
            $sell = $goods_info['sell'];
            if ($total < $num) {
                return '庫存不足';
            }
            $data['total'] = $total-$num;
            $data['sell'] = $sell+$num;
            $res = Db::table('goods')->where(['id'=>$goods_id])->update($data);
            $order_data = [];
            $order_data['uid'] = rand(1000,9999);
            $order_data['status'] = 1;
            $order_data['goods_id'] = $goods_id;
            $order_data['order_no'] = date('YmdHis').rand(1000,10000);
            $order_data['create_time'] = date('Y-m-d H:i:s');
            $order_res = Db::table('orders')->insert($order_data);
            Db::commit();
        } catch (\Exception $e) {
            // 回滾事務
            Db::rollback();
            echo $e->getMessage();
            exit('rollback');
 
        }
        echo '請求成功';
    }
 
}

使用jmeter工具測試,創(chuàng)建線程測試組:

關于使用jmeter創(chuàng)建測試高并發(fā)例子,可查看:使用JMeter進行高并發(fā)測試_左右..的博客-CSDN博客_jmeter高并發(fā)測試

這里模擬1s內(nèi)1000個用戶同時訪問

?創(chuàng)建http請求:

添加察看結(jié)果樹:

?測試開始:

100個商品不加鎖的結(jié)果:

100個商品庫存,生成訂單187個,超賣87個商品,這在項目開發(fā)中是絕對不允許的。

100個商品,加鎖結(jié)果:

?加鎖,得到解決。

到此這篇關于thinkphp6使用mysql悲觀鎖解決商品超賣問題的實現(xiàn)的文章就介紹到這了,更多相關thinkphp6 商品超賣內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

调兵山市| 游戏| 托克托县| 岳西县| 安岳县| 九寨沟县| 浪卡子县| 长岭县| 台中县| 松原市| 邓州市| 乐山市| 清涧县| 醴陵市| 合水县| 二连浩特市| 东兴市| 永州市| 建瓯市| 望奎县| 宜良县| 通州市| 大洼县| 乌拉特前旗| 临潭县| 怀来县| 岑巩县| 丹寨县| 宝应县| 河北区| 喀喇沁旗| 芷江| 汉阴县| 蓬溪县| 晋宁县| 中牟县| 七台河市| 云南省| 临潭县| 德保县| 嘉禾县|