Рубрики
Uncategorized

PHP использует redis для решения проблемы перепроданности

Автор оригинала: David Wong.

предисловие

В случае второго убийства товаров, например, запас товаров составляет всего 100, но при срочной закупке 200 человек могут спешить покупать одновременно, поэтому существует параллелизм. Если заказ на 100 товаров завершен, а запасы равны 0, он может продолжить успешное размещение заказа и будет перепродан.

Чтобы решить эту проблему, сегодня я буду в основном говорить об использовании очереди redis. У Redis есть тип списка, который на самом деле является двусторонним связанным списком. Добавляйте и удаляйте элементы из начала или конца связанного списка с помощью операций push и pop. Это позволяет использовать список либо как стек, либо как очередь. Первый вход, первый выход, один конец, один конец, это очередь. В очереди первый будет следовать за последним, поэтому очередь redis может идеально решить проблему параллелизма перепроданности.

Существуют также способы решения проблемы: 1. Использование эксклюзивной блокировки транзакций MySQL для решения; 2. Использование блокировки файлов. 3. Используйте setnx redis для реализации механизма блокировки. Проверьте и нажмите: четыре способа избежать перепроданности

Принцип осуществления

Запасы продуктов циклически увеличиваются с помощью push, а затем каждый раз при размещении заказа через rpop выводится один продукт. Когда значение num равно 0, заказ останавливается.

Шаг 1 создайте таблицу

Существует три таблицы: таблица заказов, таблица товаров и таблица журналов.

1. Форма заказа

CREATE TABLE `ims_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_sn` char(32) NOT NULL,
  `user_id` int(11) NOT NULL,
  `status` int(11) NOT NULL DEFAULT '0',
  `goods_id` int(11) NOT NULL DEFAULT '0',
  `sku_id` int(11) NOT NULL DEFAULT '0',
  `number` int(11) NOT NULL,
  `Price ` int (10) not null comment 'price: unit: Min',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_ Increment = 5820 default charset = utf8 comment ='order table '

2. Перечень товаров

CREATE TABLE `ims_hotmallstore_goods` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `Name ` varchar (50) not null comment 'commodity name',
  `type_ ID ` int (11) not null comment 'commodity classification',
  `IMG ` text not null comment 'product picture',
  `Money ` decimal (10,2) not null comment 'selling price',
  `Money2 ` decimal (10,2) not null comment 'original price',
  `is_ Show ` int (11) not null default '1' comment '1,
  `Uniacid ` int (11) not null comment 'applet ID',
  `Inventory ` int (11) not null comment 'inventory',
  `Details ` text not null comment 'details',
  `store_ ID ` int (11) not null comment 'merchant ID',
  `Sales ` int (11) not null comment 'sales',
  `logo` varchar(100) NOT NULL,
  `num` int(11) NOT NULL,
  `is_ GG ` int (11) not null default '2' comment 'enable specification',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

3. Таблица журналов

CREATE TABLE `ims_order_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `status` int(11) NOT NULL DEFAULT '0',
  `msg` text CHARACTER SET utf8,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `status` (`status`)
) ENGINE=InnoDB AUTO_ Increment = 4562 default charset = GB2312 comment ='order log table '

Шаг 2 напишите код

class Test {

    private static $instance = null;

    //Instantiating redis in single column mode
    public static function Redis()
    {
        if (self::$instance == null) {
            $redis=new \Redis();
            $redis->connect('127.0.0.1',6379);
            self::$instance = $redis;
        }
        return self::$instance;
    }

    //Cycle the inventory of goods to the num of lpush
    public function doPageSaveNum()
    {
        $redis=self::Redis();
        $goods_id=1;
        $sql="select id, num, money from ims_hotmallstore_goods where id=".$goods_id;
        $goods=pdo_fetch($sql);
        if(!empty($goods)){
         for($i=1; $i<=$goods['num']; $i++){
             $redis->lpush('num',$i);
         }
         Die! ).
        }else{
         $this - > echomsg (0, 'product does not exist. ).
        }
    }

    //Rush to order
    public function doPageGoodsStore()
    {       
            $goods_id=1;
            $sql="select id, num, money from ims_hotmallstore_goods where id=".$goods_id;
            $goods=pdo_fetch($sql);
            $redis=self::Redis();
            $count = $redis - > rpop ('num '); // take 1 from num each time
            if($count==0){
                $this->echoMsg(0,'no num redis');
            }
            $this->doPageGoodsOrder($goods,1);
            
    }

    //Save log
    public function echoMsg($status,$msg,$_data="")
    { 
      
        $data=json_encode(array('status'=>$status,'msg'=>$msg,'data'=>$_data),JSON_UNESCAPED_UNICODE);
        $order_log['status']=$status;
        $order_log['msg']=$msg;
        $order_log['create_time']=time();
        pdo_insert('order_log',$order_log);
       die($data);
    }
    public function orderNo()
    {
        return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);  
    }
    
    //Order update inventory
    public function doPageGoodsOrder($goods,$goods_number)
    {   
        $orderNo=$this->orderNo();
        $number=$goods['num']-$goods_number;
        if($number<0){
            $this - > echomsg (0, 'no inventory');
        }
        $user_id=rand(1,500);
        $order['user_id']=$user_id;
        $order['goods_id']=$goods['id'];
        $order['number']=$goods_number;
        $order['price']=$goods['money'];
        $order['status']=1;
        $order['sku_id']=2;
        $order['order_sn']=$orderNo;
        $order['create_time']=date('Y-m-d H:i:s');
        pdo_insert('order',$order);
        $sql="update ims_hotmallstore_goods set num=num-".$goods_number." where num>0 and id=".$goods['id'];
        $res=pdo_query($sql);
        if(!empty($res)){
            $this - > echomsg (1, $number of inventory deduction succeeded ');
        }
        $redis=self::Redis();
        $redis->lpush('num',$goods_number);
        $this - > echomsg (0, inventory deduction failed. $number);

    }
 }

//Call -- to cycle the inventory of goods into num of lpush
if($_GET['i']==1){
   $model = new Test;
   $model->doPageSaveNum();
}

//Call -- high concurrency rush order
if($_GET['i']==2){
   $model = new Test;
   $model->doPageGoodsStore();
}

Шаг 3 параллельный тест

1. Выполните вручную: http://127.0.0.1/wqchunjingsvn/web/index. php ?i=1 И сохраните цикл инвентаризации до числа push.

2. Здесь я использую метод тестирования и установки Apache AB, чтобы сделать дополнение в конце этой статьи. Откройте терминал и выполните: ab-n 1000-c 200 (- N отправляет 1000 запросов, – C имитирует параллелизм 200, и количество запросов должно быть больше или равно количеству одновременных запросов. 1000 человек посещают одновременно, за которыми следует тестовый URL-адрес)

3. Проверьте, успешно ли выполнено выполнение. Результат выполнения показан на рисунке ниже, что указывает на успешное выполнение.

Шаг 4 просмотр таблицы данных

1. Проверьте таблицу заказов, общее количество заказов составляет 100, как показано на рисунке ниже, никаких проблем.

2. Проверьте запасы товаров. Он изменился со 100 на 0, что не является проблемой.

3. Проверьте таблицу журнала. Всего существует 137 записей, из которых только 100 записей имеют статус 1.

Резюме и анализ

1. Схема выполнима, запасы равны 0, и перепроданности нет.

2. При использовании Apache AB для тестирования высокого параллелизма необходимо отметить, что URL-адрес не может быть соединен с параметром со знаком&, в противном случае выполнение завершится неудачно.

Сопутствующая информация

Использование redis для решения проблемы перепродажи PHP Как решить проблему перепродажи с высоким параллелизмом секунд Mac установите HTTP-сервер Apache (тест с Apache AB, метод установки) Подробное объяснение испытания под давлением с одновременным обновлением ab MySQL