swoole+PHP实现自动取消订单,还原库存等操作

2019年6月20日 308点热度 0人点赞 0条评论

图片

文章来自:CSDN
链接:
https://blog.csdn.net/WanTianwen/article/details/82693677
作者:wantianwen

商务合作:请加微信(QQ):2230304070










































图片

视频教程分享

图片

视频教程有很多,基础的,进阶的,实战的,有查看文章的都会知道,我都会在这里带上一些视频教程。有需要的可以获取,我还是希望你获取的视频教程不是用来收藏的,而是用来计划学习的。

用公众号每天来阅读文章,学习,目前是最方便的。这是自闲暇的时间里,利用5分钟读读技术文章,丰富自己的知识。。。当然,学习有很多种方法,不单单是基于公众号来学习,你可以到网上查找更多的教程,学习文档,技术书本,视频教程!各有各的爱好吧!

今天分享的视频教程

laravel5与微信公账号之分销商城开发

链接:http://blog.startphp.cn/thread-30-1-1.html


博客地址:http://www.startphp.cn

看上去博客又不像是博客,但是有时候用来收藏自己的学习笔记,或者是网上比较好的文章,总结类的文章,足矣,但是后期还是需要更多的优化。也建议大家自己动手做一个小博客,用来平时在开发中记下自己遇到的问题,记下笔记。同时提升自己,也能帮助到大家!博客地址:http://www.startphp.cn

码农程序视频学习与交流:http://blog.startphp.cn

最近整合了一个视频学习网站:码农程序社区与交流,还有很大的改善空间,望有些高人来指点,论自己注册一个账号,以后你们可以自己发帖子了,有问题的也可以抛出来一起交流与学习。小编会把收藏的web视频教程都放在这个网站里,这里有直接获取的视频教程,有需要关注公众号后获取的视频教程,也有一些高质量需要付费的视频教程。我都会慢慢的整理。视频教程以链接+提取码的形式,有需要的欢迎!视频教程网址:http://blog.startphp.cn







图片

文章正文

图片

一、业务场景:当客户下单在指定的时间内如果没有付款,那我们需要将这笔订单取消掉,比如好的处理方法是运用延时取消,这里我们用到了swoole,运用swoole的异步毫秒定时器不会影响到当前程序的运行,具体参考:https://wiki.swoole.com/wiki/page/319.html

二、说明,order_status为1时代表客户下单确定,为2时代表客户已付款,为0时代表订单已取消(正是swoole来做的),下面的代表我没有用框架,比较纯的PHP代表方便理解和应用

三、举例说明,库存表csdn_product_stock产品ID为1的产品库存数量为20,产品ID为2的库存数量为40,然后客户下单一笔产品ID1减10,产品ID2减20,所以库存表只够2次下单,例子中10秒后自动还原库存,如下图:

图解:1、第一次下完单产品ID1库存从20减到了10,产品ID2库存从40减到了20;2、第二次下完单产品ID的库存为0了,产品ID2的库存也为0了,3、第三次下单时,程序提示Out of stock;4、过了10秒钟(每个订单下单后往后推10秒),客户两次下单,由于没有付款(csdn_order表的order_status为1),产品1和产品2的库存被还原了(csdn_order表的order_status变为0),客户又可以继续下单了

图片

 

1、所需要sql数据库表

DROP TABLE IF EXISTS `csdn_order`;
CREATE TABLE `csdn_order` (
  `order_id` int(10unsigned NOT NULL AUTO_INCREMENT,
  `order_amount` float(10,2unsigned NOT NULL DEFAULT '0.00',
  `user_name` varchar(64CHARACTER SET latin1 NOT NULL DEFAULT '',
  `order_status` tinyint(2unsigned 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(10unsigned NOT NULL AUTO_INCREMENT,
  `order_id` int(10unsigned NOT NULL,
  `product_id` int(10NOT NULL,
  `product_price` float(10,2NOT NULL,
  `product_number` smallint(4unsigned 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(10unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(10NOT NULL,
  `product_stock_number` int(10unsigned 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');

2、数据库配置信息:config.php

<?php
$dbHost = "192.168.0.110";
$dbUser = "root";
$dbPassword = "123456";
$dbName = "test123";
?>

3、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(
        '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();
}
?>

4、order_cancel.php,这个方法主要就是做订单自动取消,并还原库存的业务处理

<?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(10000function ($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 . "\n");
    fclose($fh);
}
?>

以上是文章全部内容,有学习与经验交流的友友可以加小编为好友。有技术问题可以一起探讨与交流,希望你是学习技术的。


让学习成为一种习惯


微信公众号:php自学中心

长按二维码加好友 

图片

学习  |  交流  |  分享  |  文章

35470swoole+PHP实现自动取消订单,还原库存等操作

这个人很懒,什么都没留下

文章评论