swooleは注文の遅延処理を実現する(自動注文キャンセル、在庫還元などの操作)


一、ビジネスシーン:お客様の注文が指定された時間内に支払われていない場合は、この注文をキャンセルする必要があります.例えば、良い処理方法は遅延キャンセルを運用することです.多くの人がまず考えているのはcrontabです.これもいいですが、ここではswooleの非同期ミリ秒タイマーを運用して実現します.現在のプログラムの実行にも影響しません.詳細については、以下を参照してください.https://wiki.swoole.com/wiki/page/319.html
 
二、説明、order_statusが1の場合は顧客の注文を表し、2の場合は顧客の支払いを表し、0の場合は注文がキャンセルされたことを表します(swooleがやったのです)
 
三、例として、在庫表csdn_product_stock製品IDが1の製品在庫数量が20で、製品IDが2の在庫数量が40で、それからお客様が注文した製品ID 1が10減少し、製品ID 2が20減少したので、在庫表は2回しか注文できません.例では10秒後に自動的に在庫を還元します.以下の図になります.
図解:1、初めて注文した製品ID 1の在庫が20から10に減少し、製品ID 2の在庫が40から20に減少した.2、2回目の注文完了製品IDの在庫は0で、製品ID 2の在庫も0で、3、3回目の注文時、プログラムはOut of stockを提示する.4、10秒後(注文ごとに10秒後に押す)、顧客が2回注文したが、支払いがない(csdn_orderテーブルのorder_statusは1)ため、製品1と製品2の在庫が還元され(csdn_orderテーブルのorder_statusは0になる)、顧客はまた注文を続けることができる.
1、必要なsqlデータベース表
下には純粋な手作りPHPが貼られています.多くの学生が原生PHPを使っているので、フレームワークには使えません.実は同じです.そんなに複雑に考えないでください.少しだけ使いすぎると、そう思いますよ.
プロファイルconfig.php、これはフレームワークでは、基本的に配置されています.
$dbHost = "192.168.23.110";
$dbUser = "root";
$dbPassword = "123456";
$dbName = "test";

swooleはlinuxシステムで使用されています.ここのhostは自分で仮想ホストを構築したり、ネットで自分のサーバーを購入したりすることができます.
 
オーダー送信ファイルorder_submit.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(
        'order_amount' => 10.92,
        'user_name' => 'yusan',
        'order_status' => 1,
        'date_created' => 'now()',
        'product_lit' => array(
            0 => array(
                'product_id' => 1,
                'product_price' => 5.00,
                'product_number' => 10,
                'date_created' => 'now()'
            ),
            1 => array(
                'product_id' => 2,
                'product_price' => 5.92,
                'product_number' => 20,
                'date_created' => 'now()'
            )
        )
    );

    try{
        $pdo->beginTransaction();//      

        $sql = 'insert into csdn_order (order_amount, user_name, order_status, date_created) values (:orderAmount, :userName, :orderStatus, now())';
        $stmt = $pdo->prepare($sql);  
        $affectedRows = $stmt->execute(array(':orderAmount' => $orderInfo['order_amount'], ':userName' => $orderInfo['user_name'], ':orderStatus' => $orderInfo['order_status']));
        $orderId = $pdo->lastInsertId();
        if(!$affectedRows) {
            throw new PDOException("Failure to submit order!");
        }
        foreach($orderInfo['product_lit'] as $productInfo) {

            $sqlProductDetail = 'insert into csdn_order_detail (order_id, product_id, product_price, product_number, date_created) values (:orderId, :productId, :productPrice, :productNumber, now())';
            $stmtProductDetail = $pdo->prepare($sqlProductDetail);  
            $stmtProductDetail->execute(array(':orderId' => $orderId, ':productId' =>  $productInfo['product_id'], ':productPrice' => $productInfo['product_price'], ':productNumber' => $productInfo['product_number']));

            $sqlCheck = "select product_stock_number from csdn_product_stock where product_id=:productId";  
            $stmtCheck = $pdo->prepare($sqlCheck);  
            $stmtCheck->execute(array(':productId' => $productInfo['product_id']));  
            $rowCheck = $stmtCheck->fetch(PDO::FETCH_ASSOC);
            if($rowCheck['product_stock_number'] < $productInfo['product_number']) {
                throw new PDOException("Out of stock, Failure to submit order!");
            }


            $sqlProductStock = 'update csdn_product_stock set product_stock_number=product_stock_number-:productNumber, date_modified=now() where product_id=:productId';
            $stmtProductStock = $pdo->prepare($sqlProductStock);  
            $stmtProductStock->execute(array(':productNumber' => $productInfo['product_number'], ':productId' => $productInfo['product_id']));
            $affectedRowsProductStock = $stmtProductStock->rowCount();

            //        ,  ,     product_stock_number       
            //       ,sql  :SQLSTATE[22003]: Numeric value out of range: 1690 BIGINT UNSIGNED value is out of range in '(`test`.`csdn_product_stock`.`product_stock_number` - 20)'
            if($affectedRowsProductStock <= 0) {
                throw new PDOException("Out of stock, Failure to submit order!");
            }
        }
        echo "Successful, Order Id is:" . $orderId .",Order Amount is:" . $orderInfo['order_amount'] . "。";
        $pdo->commit();//    
        //exec("php order_cancel.php -a" . $orderId . " &");
        pclose(popen('php order_cancel.php -a ' . $orderId . ' &', 'w'));
        //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
require("config.php");
$queryString = getopt('a:');
$userParams = array($queryString);
appendLog(date("Y-m-d H:i:s") . "\t" . $queryString['a'] . "\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['a'];  
            $sql = "select order_status from csdn_order where order_id=:orderId";  
            $stmt = $pdo->prepare($sql);  
            $stmt->execute(array(':orderId' => $orderId));  
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            //$row['order_status'] === "1"     ,    ,               
            if(isset($row['order_status']) && $row['order_status'] === "1") {
                $sqlOrderDetail = "select product_id, product_number from csdn_order_detail where order_id=:orderId";  
                $stmtOrderDetail = $pdo->prepare($sqlOrderDetail);  
                $stmtOrderDetail->execute(array(':orderId' => $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(':productNumber' => $rowOrderDetail['product_number'], ':productId' => $rowOrderDetail['product_id']));
                }

                $sqlRestoreOrder = "update csdn_order set order_status=:orderStatus where order_id=:orderId";  
                $stmtRestoreOrder = $pdo->prepare($sqlRestoreOrder);
                $stmtRestoreOrder->execute(array(':orderStatus' => 0, ':orderId' => $orderId));
            }

            $pdo->commit();//    
        }catch(PDOException $e){
            echo $e->getMessage();
            $pdo->rollback();
        }
        $pdo = null;

        appendLog(date("Y-m-d H:i:s") . "\t" . $queryString['a'] . "\t" . "end\t" . json_encode($queryString));
    }, $pdo);

} catch (PDOException $e) {
    echo $e->getMessage();
}
function appendLog($str) {
    $dir = 'log.txt';
    $fh = fopen($dir, "a");
    fwrite($fh, $str . "
"); fclose($fh); }