>  기사  >  PHP 프레임워크  >  이번에는 주문을 지연하고 재고를 복원하기 위해 Swoole을 사용했습니다!

이번에는 주문을 지연하고 재고를 복원하기 위해 Swoole을 사용했습니다!

藏色散人
藏色散人앞으로
2021-07-30 14:09:262707검색

이번에는 주문을 지연하고 재고를 복원하기 위해 Swoole을 사용했습니다!

1. 비즈니스 시나리오: 고객이 주문을 하고 지정된 시간 내에 결제하지 않으면 주문을 취소해야 합니다. 예를 들어 지연 취소를 사용하는 것이 좋습니다. , 많은 사람들이 가장 먼저 생각하는 것은 Crontab입니다. 이것도 가능하지만 여기서는 swoole의 비동기 밀리초 타이머를 사용하여 구현하며 이는 현재 프로그램 실행에도 영향을 미치지 않습니다.

2. 설명, order_status가 1이면 주문이 완료되었음을 의미하고, 2이면 결제가 완료되었음을 의미하며, 0이면 주문이 취소되었음을 의미합니다(이것은 swoole이 하는 일입니다)

세 가지 예를 들어 재고 테이블 csdn_product_stock product 제품 ID 1의 재고 수량이 20이고, 제품 ID 2의 재고 수량이 40입니다. 그러면 고객이 주문하면 제품 ID1이 줄어듭니다. 10만큼, 제품 ID2는 20만큼 감소합니다. 따라서 재고 테이블은 2개의 주문에만 충분합니다. 예에서는 10초 후에 자동으로 재고를 복원합니다.

아래 그림과 같이

1. 처음 주문한 후 제품 ID1의 재고가 20개에서 10개로 줄었고, 제품 ID2의 재고도 40개에서 20개로 줄었습니다. 두 번째 주문 시 제품 ID의 재고는 0 이고, 제품 ID2의 재고도 0입니다.

3. 세 번째 주문 시 프로그램은

4라는 메시지를 표시합니다. 10초(각 주문마다 10초씩 푸시됨), 고객이 두 번 주문을 했습니다. 결제가 없었으므로(csdn_order 테이블의 order_status는 1입니다.) 제품 1과 제품 2의 재고가 복원되었습니다(csdn_order의 order_status). 테이블이 0이 됨), 고객은 계속 주문할 수 있습니다

이번에는 주문을 지연하고 재고를 복원하기 위해 Swoole을 사용했습니다!

1. 필수 SQL 데이터베이스 테이블

DROP TABLE IF EXISTS `csdn_order`;
CREATE TABLE `csdn_order` (
  `order_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_amount` float(10,2) unsigned NOT NULL DEFAULT '0.00',
  `user_name` varchar(64) CHARACTER SET latin1 NOT NULL DEFAULT '',
  `order_status` tinyint(2) unsigned NOT NULL DEFAULT '0',
  `date_created` datetime NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `csdn_order_detail`;
CREATE TABLE `csdn_order_detail` (
  `detail_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_id` int(10) unsigned NOT NULL,
  `product_id` int(10) NOT NULL,
  `product_price` float(10,2) NOT NULL,
  `product_number` smallint(4) unsigned NOT NULL DEFAULT '0',
  `date_created` datetime NOT NULL,
  PRIMARY KEY (`detail_id`),
  KEY `idx_order_id` (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `csdn_product_stock`;
CREATE TABLE `csdn_product_stock` (
  `auto_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(10) NOT NULL,
  `product_stock_number` int(10) unsigned NOT NULL,
  `date_modified` datetime NOT NULL,
  PRIMARY KEY (`auto_id`),
  KEY `idx_product_id` (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `csdn_product_stock` VALUES ('1', '1', '20', '2018-09-13 19:36:19');
INSERT INTO `csdn_product_stock` VALUES ('2', '2', '40', '2018-09-13 19:36:19');

이 아래에 순수 수동 PHP로 게시되어 있으며 많은 학생들이 기본 PHP를 사용하므로 프레임워크에 적용하지 않습니다. 사실 다 똑같으니 너무 복잡하게 생각하지 마세요. 너무 많이 사용하면 이런 느낌이 들 것입니다.

구성 파일 config.php, 프레임워크에 있으면 기본적으로 구성되어 있습니다.

<?php
$dbHost = "192.168.23.110";
$dbUser = "root";
$dbPassword = "123456";
$dbName = "test";
?>

swoole은 모두 Linux 시스템에서 사용됩니다. 여기서 호스트용 가상 호스트를 구축하거나 온라인으로 자체 서버를 구입할 수 있습니다.

여기에서 주문 제출 파일 order_submit.php가 생성되고 재고가 차감됩니다. 일련의 작업

<?php
require("config.php");
try {
    $pdo = new PDO("mysql:host=" . $dbHost . ";dbname=" . $dbName, $dbUser, $dbPassword, array(PDO::ATTR_PERSISTENT => true));
    $pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $orderInfo = array(
        &#39;order_amount&#39; => 10.92,
        &#39;user_name&#39; => &#39;yusan&#39;,
        &#39;order_status&#39; => 1,
        &#39;date_created&#39; => &#39;now()&#39;,
        &#39;product_lit&#39; => array(
            0 => array(
                &#39;product_id&#39; => 1,
                &#39;product_price&#39; => 5.00,
                &#39;product_number&#39; => 10,
                &#39;date_created&#39; => &#39;now()&#39;
            ),
            1 => array(
                &#39;product_id&#39; => 2,
                &#39;product_price&#39; => 5.92,
                &#39;product_number&#39; => 20,
                &#39;date_created&#39; => &#39;now()&#39;
            )
        )
    );
    try{
        $pdo->beginTransaction();//开启事务处理
        $sql = &#39;insert into csdn_order (order_amount, user_name, order_status, date_created) values (:orderAmount, :userName, :orderStatus, now())&#39;;
        $stmt = $pdo->prepare($sql);  
        $affectedRows = $stmt->execute(array(&#39;:orderAmount&#39; => $orderInfo[&#39;order_amount&#39;], &#39;:userName&#39; => $orderInfo[&#39;user_name&#39;], &#39;:orderStatus&#39; => $orderInfo[&#39;order_status&#39;]));
        $orderId = $pdo->lastInsertId();
        if(!$affectedRows) {
            throw new PDOException("Failure to submit order!");
        }
        foreach($orderInfo[&#39;product_lit&#39;] as $productInfo) {
            $sqlProductDetail = &#39;insert into csdn_order_detail (order_id, product_id, product_price, product_number, date_created) values (:orderId, :productId, :productPrice, :productNumber, now())&#39;;
            $stmtProductDetail = $pdo->prepare($sqlProductDetail);  
            $stmtProductDetail->execute(array(&#39;:orderId&#39; => $orderId, &#39;:productId&#39; =>  $productInfo[&#39;product_id&#39;], &#39;:productPrice&#39; => $productInfo[&#39;product_price&#39;], &#39;:productNumber&#39; => $productInfo[&#39;product_number&#39;]));
            $sqlCheck = "select product_stock_number from csdn_product_stock where product_id=:productId";  
            $stmtCheck = $pdo->prepare($sqlCheck);  
            $stmtCheck->execute(array(&#39;:productId&#39; => $productInfo[&#39;product_id&#39;]));  
            $rowCheck = $stmtCheck->fetch(PDO::FETCH_ASSOC);
            if($rowCheck[&#39;product_stock_number&#39;] < $productInfo[&#39;product_number&#39;]) {
                throw new PDOException("Out of stock, Failure to submit order!");
            }
            $sqlProductStock = &#39;update csdn_product_stock set product_stock_number=product_stock_number-:productNumber, date_modified=now() where product_id=:productId&#39;;
            $stmtProductStock = $pdo->prepare($sqlProductStock);  
            $stmtProductStock->execute(array(&#39;:productNumber&#39; => $productInfo[&#39;product_number&#39;], &#39;:productId&#39; => $productInfo[&#39;product_id&#39;]));
            $affectedRowsProductStock = $stmtProductStock->rowCount();
            //库存没有正常扣除,失败,库存表里的product_stock_number设置了为非负数
            //如果库存不足时,sql异常:SQLSTATE[22003]: Numeric value out of range: 1690 BIGINT UNSIGNED value is out of range in &#39;(`test`.`csdn_product_stock`.`product_stock_number` - 20)&#39;
            if($affectedRowsProductStock <= 0) {
                throw new PDOException("Out of stock, Failure to submit order!");
            }
        }
        echo "Successful, Order Id is:" . $orderId .",Order Amount is:" . $orderInfo[&#39;order_amount&#39;] . "。";
        $pdo->commit();//提交事务
        //exec("php order_cancel.php -a" . $orderId . " &");
        pclose(popen(&#39;php order_cancel.php -a &#39; . $orderId . &#39; &&#39;, &#39;w&#39;));
        //system("php order_cancel.php -a" . $orderId . " &", $phpResult);
        //echo $phpResult;
    }catch(PDOException $e){
        echo $e->getMessage();
        $pdo->rollback();
    }
    $pdo = null;
} catch (PDOException $e) {
    echo $e->getMessage();
}
?>

주문 처리 지연 order_cancel.php

<?php
require("config.php");
$queryString = getopt(&#39;a:&#39;);
$userParams = array($queryString);
appendLog(date("Y-m-d H:i:s") . "\t" . $queryString[&#39;a&#39;] . "\t" . "start");
try {
    $pdo = new PDO("mysql:host=" . $dbHost . ";dbname=" . $dbName, $dbUser, $dbPassword, array(PDO::ATTR_PERSISTENT => true));
    $pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    swoole_timer_after(10000, function ($queryString) {
        global $queryString, $pdo;
        try{
            $pdo->beginTransaction();//开启事务处理
            $orderId = $queryString[&#39;a&#39;];  
            $sql = "select order_status from csdn_order where order_id=:orderId";  
            $stmt = $pdo->prepare($sql);  
            $stmt->execute(array(&#39;:orderId&#39; => $orderId));  
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            //$row[&#39;order_status&#39;] === "1"代表已下单,但未付款,我们还原库存只针对未付款的订单
            if(isset($row[&#39;order_status&#39;]) && $row[&#39;order_status&#39;] === "1") {
                $sqlOrderDetail = "select product_id, product_number from csdn_order_detail where order_id=:orderId";  
                $stmtOrderDetail = $pdo->prepare($sqlOrderDetail);  
                $stmtOrderDetail->execute(array(&#39;:orderId&#39; => $orderId));  
                while($rowOrderDetail = $stmtOrderDetail->fetch(PDO::FETCH_ASSOC)) {
                    $sqlRestoreStock = "update csdn_product_stock set product_stock_number=product_stock_number + :productNumber, date_modified=now() where product_id=:productId";  
                    $stmtRestoreStock = $pdo->prepare($sqlRestoreStock);
                    $stmtRestoreStock->execute(array(&#39;:productNumber&#39; => $rowOrderDetail[&#39;product_number&#39;], &#39;:productId&#39; => $rowOrderDetail[&#39;product_id&#39;]));
                }
                $sqlRestoreOrder = "update csdn_order set order_status=:orderStatus where order_id=:orderId";  
                $stmtRestoreOrder = $pdo->prepare($sqlRestoreOrder);
                $stmtRestoreOrder->execute(array(&#39;:orderStatus&#39; => 0, &#39;:orderId&#39; => $orderId));
            }
            $pdo->commit();//提交事务
        }catch(PDOException $e){
            echo $e->getMessage();
            $pdo->rollback();
        }
        $pdo = null;
        appendLog(date("Y-m-d H:i:s") . "\t" . $queryString[&#39;a&#39;] . "\t" . "end\t" . json_encode($queryString));
    }, $pdo);
} catch (PDOException $e) {
    echo $e->getMessage();
}
function appendLog($str) {
    $dir = &#39;log.txt&#39;;
    $fh = fopen($dir, "a");
    fwrite($fh, $str . "\n");
    fclose($fh);
}
?>

더 많은 swoole 기술 기사를 보려면 swoole tutorial 칼럼을 방문하세요!

위 내용은 이번에는 주문을 지연하고 재고를 복원하기 위해 Swoole을 사용했습니다!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 磊丰에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제